手写经典双向循环链表
Posted stoneandatao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手写经典双向循环链表相关的知识,希望对你有一定的参考价值。
问:写出双向循环链表,并写出增、删、查
思路:一个链表要知道从哪里开始,所以要有头,还要知道有多大,所以要有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
以上是关于手写经典双向循环链表的主要内容,如果未能解决你的问题,请参考以下文章