双向循环链表中,每个节点都有2个指针,分别指向前一个节点和后一个节点。
链表头有一个head,是空节点,head节点的前一个节点指向链表最后一个节点,链表最后一个节点的后一个节点是head节点。
查询的时候,如果index小于链表长度一半,从头开始查询,如果index长度大于链表长度一半,则从末尾开始查询。故,时间复杂度是O(n/2)
内存空间不一定是连续的,由于查询需要遍历每一个节点,并取获节点的next节点。遍历查询效率不如数组。但是中间的插入,删除的效率优于数组。
在java中,linkedList就是依赖双链表实现的。
下面是手撸实现的记录:
public class Doublelink{ private DNode mHead; //头节点 private int mCount; //节点个数 public Doublelink() { mHead = new DNode (null, null, null); mHead.pre = mHead.next = mHead; mCount = 0; } public int size() { return mCount; } private DNode getNode(int index) { if (index < 0 || index >= mCount) { throw new IndexOutOfBoundsException(); } //正向查找 if (index < mCount / 2) { DNode node = mHead.next; for (int i = 0; i < index; i++) { node = node.next; } return node; } //反向查找 DNode node = mHead.pre; //画图就能看出来,反过来算index = 末尾指针(mCount-1) - 目标index(index) int rIndex = mCount - 1 - index; for (int i = 0; i < rIndex; i++) { node = node.pre; } return node; } //获取第i个位置的节点的值 public T get(int index) { return getNode(index).value; } public T getLast() { return getNode(mCount - 1).value; } //将节点插入到index位置之前 public void add(int index, T t) { if (index < 0 || index > mCount) { throw new IndexOutOfBoundsException(); } if (index == 0) { //根据参数t,和位置0,创建了一个我们需要插入的值 DNode node = new DNode<>(mHead, mHead.next, t); //将原本head的下一个节点的向上的指针指向我们的目标node mHead.next.pre = node; //头节点的下一个指针,指向我们的node mHead.next = node; } else { DNode nextNode = getNode(index); //创建我们的目标node DNode node = new DNode<>(nextNode.pre, nextNode, t); nextNode.pre.next = node; nextNode.pre = node; } //不要忘记了! mCount++; } public void addFirst(T t) { add(0, t); } //末尾插入 public void add(T t) { if (mCount == 0) { addFirst(t); } else { DNode node = new DNode<>(mHead.pre, mHead, t); mHead.pre.next = node; mHead.pre = node; mCount++; } } //删除节点 public void delete(int index) { DNode node = getNode(index); DNode nodePre = node.pre; node.next.pre = nodePre.pre; mCount--; } //删除第一个个节点 public void deleteFirst() { delete(0); } //删除最后一个节点 public void deleteLast() { delete(mCount - 1); } private static class DNode { DNode pre; DNode next; T value; public DNode(DNode pre, DNode next, T value) { this.pre = pre; this.next = next; this.value = value; } } }



