什么是雙向循環鏈表
在了解雙向循環鏈表之前,如果對鏈表還沒有一個清晰的概念,建議你看看單鏈表和單向循環鏈表,這有利於你更好的理解下面的內容。(廢話有點多[逃]
相比單鏈表,雙向循環鏈表是一個更加復雜的結構。因為雙向循環鏈表的節點不僅包含指向下一個節點的指針(next),還包含指向前一個節點的指針(prev)。

- 在雙向循環鏈表中,可見的不只有頭指針head,還有尾節點end。這是和單鏈表的區別。
- 雙向循環鏈表的頭指針head的前一個節點指向end,尾節點end的后一個節點指向head。
基本操作
雙向循環鏈表的基本操作有:增(add),刪(remove),改(set),查(find),插(insert)等。在這里我們只講解remove,insert和getNode操作,其他實現可看下方源碼。
獲取節點
由於雙向鏈表有兩個可見的節點(head和end),因此雙向循環鏈表獲取節點的操作和單鏈表有所不同。
- 把需要獲取的節點序號和鏈表長度/2比較
- 若小於,說明節點是偏前的,因此從head開始一路next下去
- 若大於,說明節點是偏后的,因此從end開始一路prev上去
- 這樣的設計能使getNode操作的時間復雜度縮短為O(logN)
刪除元素
- 獲取待刪除元素的節點node
- 把node前一個節點的next指針設置為node的后一個節點。具體實現為:node.prev.next=node.next
- 把node后一個節點的prev指針設置為node的前一個節點。具體實現為:node.next.prev=node.prev
- 由於沒有指針指向node,node會被自動清理
- 記錄鏈表長度的變量-1
插入元素
- 獲取待插入元素的節點node
- 創建一個節點mynode,next指向node,prev指向node.prev
- 把node.prev該節點的next指向mynode
- 把node的前一個節點prev指向mynode
雙向循環鏈表的優劣
優勢
- 相比單鏈表,雙向循環鏈表所有基本操作均快於單鏈表(java源碼的LinkList類就是雙向循環鏈表)
- 能直接獲取節點的前一個節點,十分靈活
劣勢
- 相比單鏈表,雙鏈表的空間內存明顯要大很多
雙鏈表的設計應用了算法設計的“空間換時間”思想,通過消耗更多的空間來縮小操作的時間復雜度。
源碼實現
public class Node<Anytype> {
public Anytype data;//數據
public Node<Anytype> prev;//前一個節點
public Node<Anytype> next;//后一個節點
public Node(Anytype data,Node<Anytype> prev,Node<Anytype> next){
this.data=data;
this.prev=prev;
this.next=next;
}
}
----------------------------------------------
public class DoubleLink<AnyType> {
Node<AnyType> head;//頭指針
Node<AnyType> end;//尾節點
int size;//記錄鏈表長度
//初始化鏈表
public void initlist(){
end=new Node<>(null,null,null);
head=new Node<>(null,null,end);
end.prev=head;
end.next=head;
size=0;
}
//獲取長度
public int length(){
return size;
}
//獲取節點
public Node<AnyType> getNode(int index){
Node<AnyType> n;
if(index>=size/2){
n=end;
for(int i=length();i>index;i--){
n=n.prev;
}
return n;
}
else{
n=head;
for(int i=0;i<=index;i++){
n=n.next;
}
return n;
}
}
//添加元素
public void add(AnyType a){
Node<AnyType> renode=new Node<>(a,getNode(size-1),end);
renode.prev.next=renode;
renode.next.prev=renode;
size++;
}
//插入元素
public void insert(int i,AnyType a){
Node<AnyType> n=getNode(i);
Node<AnyType> renode=new Node<>(a,n.prev,n);
n.prev.next=renode;
n.prev=renode;
size++;
}
//刪除元素
public AnyType remove(int i){
Node<AnyType> n=getNode(i);
AnyType data=n.data;
n.prev.next=n.next;
n.next.prev=n.prev;
size--;
return data;
}
//獲取i位置的數據
public AnyType get(int i){
return getNode(i).data;
}
//為i位置元素重新賦值
public AnyType set(int i,AnyType a){
Node<AnyType> n=getNode(i);
AnyType old=n.data;
n.data=a;
return old;
}
//清空鏈表
public void clear(){
initlist();
}
public void print(){
for(int i=0;i<size;i++){
System.out.println(getNode(i).data);
}
}
}