04數據結構和算法(Java描述)~雙鏈表

04數據結構和算法(Java描述)~雙鏈表

本文是上一篇文章的後續,詳情點擊該鏈接

雙鏈表的定義

      雙鏈表也叫雙向鏈表,它依舊採用的是鏈式存儲結構。在雙鏈表中,每個節點中都有兩個指針, 分別指向直接前驅節點(保存前一個節點的地址值)和直接後繼節點(保存後一個節點的地址值), 如下圖所示

在這裏插入圖片描述

      所以,從雙鏈表中的任意一個節點開始,都可以很方便地訪問它的直接前驅節點和直接後繼節 點,如下圖所示。


在這裏插入圖片描述
單鏈表和雙鏈表的區別

      邏輯上沒有區別,他們均是完成線性表的內容,主要的區別是結構上的構造有所區別。

單鏈表

      對於一個節點,有儲存數據的 data和指向下一個節點的next。也就是說,單鏈表的遍歷操作都 得通過前節點—>後節點。

在這裏插入圖片描述

雙鏈表

      對於一個節點,有儲存數據的data和指向下一個節點的 next,還有一個指向前一個節點的 pre。 也就是說,雙鏈表不但可以通過前節點—>後節點,還可以通過後節點—>前節點。

在這裏插入圖片描述

定義List接口

public interface List <E>{
    int size();
    boolean isEmpty();
    boolean contains(E element);
    void add(E element);
    E get(int index);
    E set(int index,E element);
    void add(int index,E element);
    E remove(int index);
    int indexOf(E element);
    void clear();
    String toString();
}

接口實現

public class LinkedList<E> implements List<E>{

    private int size;   //集合的長度
    private Node first;
    private Node last;

    @Override
    public int size() {
        return size;
    }

    //判斷當前集合中是否有元素
    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    //判斷當前元素是否存在
    @Override
    public boolean contains(E element) {
        return indexOf(element) > -1;
    }

    @Override
    public void add(E element) {
        //調用下面的add方法,根據size保證每次都添加在最後
        add(size,element);
    }
    //取得座標位置上的節點
    private Node<E> node(int index){
        Node N = first; //指向頭
        //先判斷要查找的index,是靠近頭還是靠近尾
        //如果靠近頭就從頭開始查找,如果靠近尾就從尾開始查找
        //方法: 根據index 和 size的一半去比較
        if(index > (size >> 1)){
            //靠近尾
            N = last;   //指向尾
            for(int i = size-1; i > index; i--){
                N = N.pre;
            }
        }else{
            //靠近頭
            for(int i = 0; i < index; i++){
                N = N.next;
            }
        }
        return N;
    }

    @Override
    public E get(int index) {
        //防止座標越界
        if(index < 0 || index >= size){
            throw  new IndexOutOfBoundsException("index: " + index + " size: " + size);
        }
        //調用方法
        return node(index).element;
    }

    @Override
    public E set(int index, E element) {
        //獲得index上的node
        Node<E> node = node(index);
        //保存原來的值
        E oldElement = node.element;
        //新值覆蓋老值
        node.element = element;
        //返回老值
        return oldElement;
    }

    @Override
    public void add(int index, E element) {
        //當需要添加到末尾時
        if(index == size) {
            //拿到last節點
            Node l = last;
            //構建node 完成指向關係
            Node newNode = new Node(l,null,element);
            //將原來的last 節點的next 修改成新構建出來的node
            last = newNode;
            if(l == null){
                first = newNode;
            }else {
                l.next = newNode;
            }
        }else{
            //獲得指定的index
            Node<E> node = node(index);
            //獲得前一個結點
            Node<E> pre = node.pre;
            //構建新的now 完成指向關係
            Node<E> newNode = new Node(pre, node, element);
            //改變指向
            pre.next = newNode;
            if (pre == null) {
                first = newNode;
            } else {
                node.pre = newNode;
            }
        }
        size++;
    }

    //鏈表刪除的主要原理就是將被刪除者的前一個元素指向後一個元素
    //比如 A->B->C  當我要刪除B的時候,就讓A -> C
    @Override
    public E remove(int index) {
        //防止座標越界
        if(index < 0 || index >= size){
            throw  new IndexOutOfBoundsException("index: " + index + " size: " + size);
        }
        //獲得要刪除的元素Node
        Node<E>node = node(index);
        //獲得前一個結點
        Node<E> pre = node.pre;
        //獲得後一個結點
        Node<E> next = node.next;

        if(pre == null){
            //firest進行修改
            first = next;
            next.pre = null;
        }else{
            //改變前一個結點的next
            pre.next = next;
        }
        
        if(next == null){
            //last進行修改
            last = pre;
        }else{
            next.pre = pre;
        }
        size--;
        //返回老元素
        return node.element;
    }

    @Override
    public int indexOf(E element) {
        //查找element元素是否存在,有返回索引,沒有返回-1
        Node N = first;
        int index = 0;
        //遍歷
        for(Node i = N; i != null; i = i.next){
            if(element == i.element){
                return index;
            }
            index++;
        }
        return -1;
    }

    @Override
    public void clear() {
        size = 0;
        first = null;
        last = null;
    }

    public String toString(){
        Node N = first;
        StringBuilder stringBuilder = new StringBuilder("[");
        boolean flag = false;   //判斷是否循環到了最後
        for(Node i = N; i != null; i = i.next){
            //說明已經到了最後一個元素
            if(i.next == null) {
                flag = true;
            }
            //如果沒到最後就加 逗號
            if(flag == false){
                stringBuilder.append(i.element + ",");
            }else{  //到了最後就不加逗號
                stringBuilder.append(i.element);
            }
        }
        stringBuilder.append("]");
        return stringBuilder.toString();
    }

    //內部Node節點類
    private static class Node<E>{
        Node<E> pre;
        Node<E> next;
        E element;
        public Node(Node next,E element){
            this.next = next;
            this.element = element;
        }

        public Node(Node pre,Node next,E element){
            this.pre = pre;
            this.next = next;
            this.element = element;
        }

        public Node() {

        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章