戀上數據結構與算法:普通雙向鏈表(六)

文章目錄

(一)雙向鏈表:簡介
(二)雙向鏈表:clear
(三)雙向鏈表:add
(四)雙向鏈表:remove
(五)雙向鏈表:測試
(六)雙向鏈表:總結
(七)雙向鏈表:源碼分析

(一)雙向鏈表:簡介

在這裏插入圖片描述
首先增加成員變量,如下:
在這裏插入圖片描述
然後修改node(int index)方法,如下:

    private Node<E> node(int index) {
        rangeCheck(index);

        if (index < (size >> 1)) {
            Node<E> node = first;
            for (int i = 0; i < index; i++) {
                node = node.next;
            }
            return node;
        } else {
            Node<E> node = last;
            for (int i = size - 1; i > index; i--) {
                node = node.prev;
            }
            return node;
        }
    }

(二)雙向鏈表:clear

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

此時節點兩兩之間互相引用,但是還是會被JVM虛擬機銷燬,因爲JVM除了看對象是否被引用,還要是否被gc root對象引用
在這裏插入圖片描述
gc root對象之一:被棧指針(局部變量)指向的對象
如果節點間接gc root對象引用着,也不會被銷燬

(三)雙向鏈表:add

頭節點的prev和尾節點的next指向的都是null
在這裏插入圖片描述
此時如果想往2號節點的位置添加節點,不需要像之前那樣通過node(int index)方法找前一個節點了,直接用prev就可以了

首先讓前一位元素(1號節點)的next指向新節點
在這裏插入圖片描述
再讓2號節點prev指向新節點
在這裏插入圖片描述
再讓新節點next指向2號節點prev指向1號節點,最後調整序號就可以了
在這裏插入圖片描述
初步代碼如下:
在這裏插入圖片描述
但是我們還要處理一些特殊情況(往頭節點/尾節點的位置添加)
在這裏插入圖片描述
最後考慮只有一個元素的情況,如下:
在這裏插入圖片描述
最開始什麼都沒有,Node<E> oldLast = last;獲取的oldLast爲null,後面執行oldLast.next = last;必然會報錯
在這裏插入圖片描述
代碼如下:
在這裏插入圖片描述

(四)雙向鏈表:remove

假設我們要刪除2號節點
在這裏插入圖片描述
首先讓前一個結點(1號結點)的next指向後一個結點(3號結點
在這裏插入圖片描述
再讓後一個結點的prev指向前一個結點
在這裏插入圖片描述
此時2號元素沒有被引用了,被銷燬,最後重新調整序號就可以了
在這裏插入圖片描述
代碼如下:
在這裏插入圖片描述
考慮邊界情況後的完整代碼如下:
(無非就是prev可能是null,next可能是null)
在這裏插入圖片描述

(五)雙向鏈表:測試

測試代碼如下:

	static void testList(List<Integer> list) {
	    list.add(11);
	    list.add(22);
	    list.add(33);
	    list.add(44);
	
	    list.add(0, 55); // [55, 11, 22, 33, 44]
	    list.add(2, 66); // [55, 11, 66, 22, 33, 44]
	    list.add(list.size(), 77); // [55, 11, 66, 22, 33, 44, 77]
	
	    list.remove(0); // [11, 66, 22, 33, 44, 77]
	    list.remove(2); // [11, 66, 33, 44, 77]
	    list.remove(list.size() - 1); // [11, 66, 33, 44]
	
	    Asserts.test(list.indexOf(44) == 3);
	    Asserts.test(list.indexOf(22) == List.ELEMENT_NOT_FOUND);
	    Asserts.test(list.contains(33));
	    Asserts.test(list.get(0) == 11);
	    Asserts.test(list.get(1) == 66);
	    Asserts.test(list.get(list.size() - 1) == 44);
	
	    System.out.println(list);
	}

爲了測試方便,修改代碼如下:
在這裏插入圖片描述
在這裏插入圖片描述
測試結果如下:
(目前只修改了LinkedList裏面的Node內部類的toString()方法)
在這裏插入圖片描述

(六)雙向鏈表:總結

在這裏插入圖片描述
在這裏插入圖片描述

(七)雙向鏈表:源碼分析

JDK官方提供的LinkedList跟我們之前寫的動態數組很相近,可以自己進去閱讀源碼
在這裏插入圖片描述
注意:JDK官方提供的LinkedList裏面的clear()方法不僅斷掉firstlast兩根線,還斷掉了結點之間的線,如下:
在這裏插入圖片描述
目的是爲了節省內存,比如在執行clear()方法的同時來了一個迭代器(屬於gc root對象)引用最後面一個節點,因爲後面的1、2、3節點都連接着,所以不會被銷燬,但是迭代器要的只是4號節點
在這裏插入圖片描述
如果把節點之間的線也斷掉,效果如下:
在這裏插入圖片描述
無關的節點就會被銷燬,如下:
在這裏插入圖片描述

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