(java實現)雙向循環鏈表


什么是雙向循環鏈表

在了解雙向循環鏈表之前,如果對鏈表還沒有一個清晰的概念,建議你看看單鏈表單向循環鏈表,這有利於你更好的理解下面的內容。(廢話有點多[逃]

相比單鏈表,雙向循環鏈表是一個更加復雜的結構。因為雙向循環鏈表的節點不僅包含指向下一個節點的指針(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);
        }
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM