(java實現)雙向循環鏈表

什麼是雙向循環鏈表

在瞭解雙向循環鏈表以前,若是對鏈表尚未一個清晰的概念,建議你看看單鏈表單向循環鏈表,這有利於你更好的理解下面的內容。(廢話有點多[逃]html

相比單鏈表,雙向循環鏈表是一個更加複雜的結構。由於雙向循環鏈表的節點不只包含指向下一個節點的指針(next),還包含指向前一個節點的指針(prev)。java

  • 在雙向循環鏈表中,可見的不僅有頭指針head,還有尾節點end。這是和單鏈表的區別。
  • 雙向循環鏈表的頭指針head的前一個節點指向end,尾節點end的後一個節點指向head。

基本操做

雙向循環鏈表的基本操做有:增(add),刪(remove),改(set),查(find),插(insert)等。在這裏咱們只講解remove,insert和getNode操做,其餘實現可看下方源碼。node

獲取節點

因爲雙向鏈表有兩個可見的節點(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類就是雙向循環鏈表)
  • 能直接獲取節點的前一個節點,十分靈活
劣勢
  • 相比單鏈表,雙鏈表的空間內存明顯要大不少

雙鏈表的設計應用了算法設計的「空間換時間」思想,經過消耗更多的空間來縮小操做的時間複雜度。this


源碼實現

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);
        }
    }
}
相關文章
相關標籤/搜索