标签:代码 下标 获取 开始 准备 throw pen builder 技术
问:写出双向循环链表,并写出增、删、查
思路:一个链表要知道从哪里开始,所以要有头,还要知道有多大,所以要有size。链表的每一个疙瘩,我们叫它节点(node),它有其本身的值,还存着上一个节点和下一个节点的引用,我们要把这些节点链起来,正着链一周,反着链一周。
1 private Node head; 2 private int size = 0; 3 private class Node{ 4 Node(E e) { 5 data = e; 6 } 7 E data; 8 Node next; 9 Node prev; 10 }
①咱先写往尾部追加元素
//追加元素 public boolean add(E e) { //如果什么都没有 if(head == null) { //把新加进来的节点作为头节点 head = new Node(e); //头节点的下一个是其本身 head.next = head; //头节点的上一个是其本身 head.prev = head; //如果刚开始有节点 }else { Node node = new Node(e); //先找到最后一个节点,它就是头节点的上一个节点 //注意:这是经典的双向循环链表,jdk8后最后一个节点是拿出来作为属性的 Node last = head.prev; //把新加进来的元素链到末尾 head.prev = node; node.prev = last; last.next = node; node.next = head; } size++; return true; }
②根据下标找对应的元素,当然,下标也是从0开始的
//根据下标获取元素 public E get(int index) { if(index < 0 || index > size) throw new IndexOutOfBoundsException("下标越界"); Node node; node = find(index); return node.data; } //根据下标获取节点 private Node find(int index) { Node node; //如果下标小于size的一半,则从头开始找 if(index < size>>1) { node = head; for(int i = 0; i < index; i++) { node = node.next; } }else { //如果下标大于size的一半,则从最后一个开始往前找 //其实一直是往后找也行,就是太笨了 node = head.prev; for(int i = size - 1; i > index; i--) { node = node.prev; } } return node; }
③add()的重载方法,根据下标和给定的元素插入节点
//根据下标插入元素e public boolean add(int index, E e) { if(index < 0 || index > size) throw new IndexOutOfBoundsException("下标越界"); //如果下标等于size,那就是追加元素,调用add方法 if(index == size) return add(e); //先根据下标找到元素,它就是即将要插入的节点的下一个节点 Node next = find(index); //再找到上一个节点 Node prev = next.prev; //准备好新节点 Node node = new Node(e); //把新节点链进来,顺时针走一波,逆时针走一波 prev.next = node; node.next = next; next.prev = node; node.prev = prev; //如果是在头部插入,再多做一个工作,就是把插入的节点作为新的头 if(index == 0) head = node; size++; return true; }
④根据下标删元素
//根据下标删元素 public E remove(int index) { if(index < 0 || index >= size) throw new IndexOutOfBoundsException("下标越界"); //如果就剩个头 if(size == 1) { //取出头节点的值 E e = head.data; //头节点被gc回收掉 head = null; size--; //返回取出来的值 return e; } //先根据下标找到要删的节点 Node node = find(index); Node prev = node.prev; Node next = node.next; //把要删的节点晾在一边 next.prev = prev; prev.next = next; //下面可写可不写,我们写明显一点,让被删的节点回收掉 node.next = null; node.prev = null; //你要是删头节点的话,把下一个节点当做新的头 if(index == 0) head = next; size--; return node.data; }
完整代码:
1 //双向循环链表 2 public class LinkedList<E> { 3 private Node head; 4 private int size = 0; 5 private class Node{ 6 Node(E e) { 7 data = e; 8 } 9 E data; 10 Node next; 11 Node prev; 12 } 13 //返回链表大小 14 public int size() { 15 return size; 16 } 17 //toString()方法 18 public String toString() { 19 if(head == null) { 20 return "[]"; 21 } 22 StringBuilder buf = new StringBuilder("["); 23 buf.append(head.data); 24 25 Node node = head.next; 26 //咱这用的是node和head的关系,当然你也可以用index和size的关系来遍历链表 27 while(node != head) { 28 //这里一个逗号一个数据是成对出现的 29 buf.append(", ").append(node.data); 30 node = node.next; 31 } 32 buf.append("]"); 33 return buf.toString(); 34 } 35 //根据下标删元素 36 public E remove(int index) { 37 38 if(index < 0 || index >= size) throw new IndexOutOfBoundsException("下标越界"); 39 //如果就剩个头 40 if(size == 1) { 41 //取出头节点的值 42 E e = head.data; 43 //头节点被gc回收掉 44 head = null; 45 size--; 46 //返回取出来的值 47 return e; 48 } 49 //先根据下标找到要删的节点 50 Node node = find(index); 51 Node prev = node.prev; 52 Node next = node.next; 53 //把要删的节点晾在一边 54 next.prev = prev; 55 prev.next = next; 56 //下面可写可不写,我们写明显一点,让被删的节点回收掉 57 node.next = null; 58 node.prev = null; 59 //你要是删头节点的话,把下一个节点当做新的头 60 if(index == 0) head = next; 61 62 size--; 63 64 return node.data; 65 } 66 67 //根据下标插入元素e 68 public boolean add(int index, E e) { 69 70 if(index < 0 || index > size) throw new IndexOutOfBoundsException("下标越界"); 71 //如果下标等于size,那就是追加元素,调用add方法 72 if(index == size) return add(e); 73 //先根据下标找到元素,它就是即将要插入的节点的下一个节点 74 Node next = find(index); 75 //再找到上一个节点 76 Node prev = next.prev; 77 //准备好新节点 78 Node node = new Node(e); 79 //把新节点链进来,顺时针走一波,逆时针走一波 80 prev.next = node; 81 node.next = next; 82 next.prev = node; 83 node.prev = prev; 84 //如果是在头部插入,再多做一个工作,就是把插入的节点作为新的头 85 if(index == 0) head = node; 86 87 size++; 88 89 return true; 90 } 91 92 //追加元素 93 public boolean add(E e) { 94 //如果什么都没有 95 if(head == null) { 96 //把新加进来的节点作为头节点 97 head = new Node(e); 98 //头节点的下一个是其本身 99 head.next = head; 100 //头节点的上一个是其本身 101 head.prev = head; 102 //如果刚开始有节点 103 }else { 104 Node node = new Node(e); 105 //先找到最后一个节点,它就是头节点的上一个节点 106 //注意:这是经典的双向循环链表,jdk8后最后一个节点是拿出来作为属性的 107 Node last = head.prev; 108 //把新加进来的元素链到末尾 109 head.prev = node; 110 node.prev = last; 111 last.next = node; 112 node.next = head; 113 } 114 size++; 115 return true; 116 } 117 118 //根据下标获取元素 119 public E get(int index) { 120 if(index < 0 || index > size) throw new IndexOutOfBoundsException("下标越界"); 121 122 Node node; 123 node = find(index); 124 return node.data; 125 126 } 127 128 //根据下标获取节点 129 private Node find(int index) { 130 Node node; 131 //如果下标小于size的一半,则从头开始找 132 if(index < size>>1) { 133 node = head; 134 for(int i = 0; i < index; i++) { 135 node = node.next; 136 } 137 138 }else { 139 //如果下标大于size的一半,则从最后一个开始往前找 140 //其实一直是往后找也行,就是太笨了 141 node = head.prev; 142 for(int i = size - 1; i > index; i--) { 143 node = node.prev; 144 } 145 } 146 return node; 147 } 148 149 }
标签:代码 下标 获取 开始 准备 throw pen builder 技术
原文地址:https://www.cnblogs.com/stoneandatao/p/11258568.html