Java集合之LinkedList常用方法解析


  最近正准備回顧一下Java,所以在此做一些記錄。

1.LinkedList使用的是鏈表結構,先看一下節點的定義

 1  /**
 2      *
 3      * 連接的節點
 4      */
 5     private static class Node<E> {
 6         //保存的數據
 7         E item;
 8         //后置節點
 9         Node<E> next;
10         //前置節點
11         Node<E> prev;
12         //構造方法
13         Node(Node<E> prev, E element, Node<E> next) {
14             this.item = element;
15             this.next = next;
16             this.prev = prev;
17         }
18     }
View Code

2.add(E e) 添加一個元素

 1  /**
 2      * 添加一個元素
 3      *
 4      * @param e 添加的元素
 5      */
 6     public boolean add(E e) {
 7         //調用添加到末尾
 8         linkLast(e);
 9         return true;
10     }
11 
12 
13 /**
14      * 添加一個元素到鏈表的尾部
15      */
16     void linkLast(E e) {
17         //獲取鏈表的尾部節點
18         final Node<E> l = last;
19         //創建新的節點,前置節點為last,后置節點為空
20         final Node<E> newNode = new Node<>(l, e, null);
21         //重新設置尾部節點
22         last = newNode;
23         //如果之前的尾部節點為空,說明之前沒有元素
24         if (l == null)
25             //設置頭節點也為空
26             first = newNode;
27         else
28             //如果之前的尾部節點不為空,則為之前的尾部節點追加后置節點
29             l.next = newNode;
30         //數量加一
31         size++;
32         modCount++;
33     }   
34  
View Code

3.add(int index, E element)  添加一個元素到指定位置

 1  /**
 2      * 添加一個元素到指定位置
 3      *
 4      * @param index 指定的位置
 5      * @param element 添加的元素
 6      */
 7     public void add(int index, E element) {
 8         //檢查指定的位置是否越界
 9         checkPositionIndex(index);
10         //如果插入的是尾部,直接調用插入尾部的方法
11         if (index == size)
12             linkLast(element);
13         else
14             //需要先找到指定位置的節點
15             // 插入到該節點之前
16             linkBefore(element, node(index));
17     }
18 
19  //檢查是否越界
20     private void checkPositionIndex(int index) {
21         if (!isPositionIndex(index))
22             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
23     }
24 
25   private boolean isPositionIndex(int index) {
26         return index >= 0 && index <= size;
27     }
28 
29 /**
30      * 查詢指定位置的節點
31      */
32     Node<E> node(int index) {
33         // 類似於二分查詢
34         // 如果位置小於集合大小的一半,從頭節點開始遍歷
35         // 否則從尾部節點開始遍歷
36 
37         if (index < (size >> 1)) {
38             Node<E> x = first;
39             for (int i = 0; i < index; i++)
40                 x = x.next;
41             return x;
42         } else {
43             Node<E> x = last;
44             for (int i = size - 1; i > index; i--)
45                 x = x.prev;
46             return x;
47         }
48     }
49 
50   /**
51      * 在某個節點之前進行插入
52      */
53     void linkBefore(E e, Node<E> succ) {
54         // 獲取當前節點的前置節點
55         final Node<E> pred = succ.prev;
56         //保存創建的新節點
57         final Node<E> newNode = new Node<>(pred, e, succ);
58         //將新節點設置為當前位置節點的前置節點
59         succ.prev = newNode;
60         //如果當前位置節點的前置節點為空,則說明當前位置為頭節點
61         if (pred == null)
62             //重新設置頭節點
63             first = newNode;
64         else
65             //將當前位置節點的前置節點的后置節點設置為新節點
66             pred.next = newNode;
67         //數量增加
68         size++;
69         modCount++;
70     }
View Code

4.get(int index) 獲取指定位置的元素

 1 /**
 2      * 獲取指定位置的元素
 3      *
 4      * @param index 指定的位置
 5      * @return 查詢到的元素
 6      */
 7     public E get(int index) {
 8         //判斷是否越界
 9         checkElementIndex(index);
10         //查詢到節點的值
11         return node(index).item;
12     }
13 
14 //檢查是否越界
15     private void checkElementIndex(int index) {
16         if (!isElementIndex(index))
17             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
18     }
19 
20   private boolean isElementIndex(int index) {
21         return index >= 0 && index < size;
22     }
23 
24  /**
25      * 查詢指定位置的節點
26      */
27     Node<E> node(int index) {
28         // 類似於二分查詢
29         // 如果位置小於集合大小的一半,從頭節點開始遍歷
30         // 否則從尾部節點開始遍歷
31 
32         if (index < (size >> 1)) {
33             Node<E> x = first;
34             for (int i = 0; i < index; i++)
35                 x = x.next;
36             return x;
37         } else {
38             Node<E> x = last;
39             for (int i = size - 1; i > index; i--)
40                 x = x.prev;
41             return x;
42         }
43     }
View Code

5.remove(Object o) 刪除指定的元素

 1  /**
 2      * 刪除指定的元素
 3      *
 4      * @param o 需要刪除的元素
 5      */
 6     public boolean remove(Object o) {
 7         //判斷需要刪除的元素是否為空
 8         if (o == null) {
 9             //如果為空,從頭節點開始遍歷
10             for (Node<E> x = first; x != null; x = x.next) {
11                 if (x.item == null) {
12                     //刪除節點
13                     unlink(x);
14                     return true;
15                 }
16             }
17         } else {
18             //刪除的元素不為為空,也是頭節點開始遍歷
19             for (Node<E> x = first; x != null; x = x.next) {
20                 if (o.equals(x.item)) {
21                     //刪除節點
22                     unlink(x);
23                     return true;
24                 }
25             }
26         }
27         return false;
28     }
29 
30  /**
31      * 刪除一個節點
32      */
33     E unlink(Node<E> x) {
34         // 獲取刪除節點的值
35         final E element = x.item;
36         //獲取刪除節點的后置節點
37         final Node<E> next = x.next;
38         //獲取刪除節點的前置節點
39         final Node<E> prev = x.prev;
40 
41         //判斷前置節點是否為空
42         if (prev == null) {
43             //為空則其后置節點晉升為頭節點
44             first = next;
45         } else {
46             //修改前置節點的后置節點
47             prev.next = next;
48             //將刪除節點的前置節點置空
49             x.prev = null;
50         }
51 
52         //判斷后置節點是否為空
53         if (next == null) {
54             //后置節點為空,則其前置節點修改為尾部節點
55             last = prev;
56         } else {
57             //后置節點的前置節點修改
58             next.prev = prev;
59             //刪除節點的后置節點置空
60             x.next = null;
61         }
62         //刪除節點的值設置為空
63         x.item = null;
64         //數量減1
65         size--;
66         modCount++;
67         return element;
68     }
View Code

6.set(int index, E element) 在指定位置節點設置值

 1  /**
 2      * 在指定位置節點設置值
 3      *
 4      * @param index 指定的位置
 5      * @param element 元素值
 6      */
 7     public E set(int index, E element) {
 8         //檢查位置是否越界
 9         checkElementIndex(index);
10         //查詢到當前位置的節點
11         Node<E> x = node(index);
12         //獲取舊值
13         E oldVal = x.item;
14         //設置新值
15         x.item = element;
16         //返回舊值
17         return oldVal;
18     }
19 
20  /**
21      * 查詢指定位置的節點
22      */
23     Node<E> node(int index) {
24         // 類似於二分查詢
25         // 如果位置小於集合大小的一半,從頭節點開始遍歷
26         // 否則從尾部節點開始遍歷
27 
28         if (index < (size >> 1)) {
29             Node<E> x = first;
30             for (int i = 0; i < index; i++)
31                 x = x.next;
32             return x;
33         } else {
34             Node<E> x = last;
35             for (int i = size - 1; i > index; i--)
36                 x = x.prev;
37             return x;
38         }
39     }
View Code

7.indexOf(Object o) 查詢指定元素值所在位置,lastIndexOf也一樣,只是從尾部節點開始查詢

 1     /**
 2      * 查詢指定元素值所在位置
 3      *
 4      * @param o 元素值
 5      */
 6     public int indexOf(Object o) {
 7         int index = 0;
 8         //判斷查詢的值是否為null
 9         if (o == null) {
10             //從頭節點開始遍歷查詢
11             for (Node<E> x = first; x != null; x = x.next) {
12                 if (x.item == null)
13                     return index;
14                 index++;
15             }
16         } else {
17             //從頭節點開始遍歷查詢
18             for (Node<E> x = first; x != null; x = x.next) {
19                 if (o.equals(x.item))
20                     return index;
21                 index++;
22             }
23         }
24         return -1;
25     }
View Code

8.peek() 獲取頭節點的元素值,但不刪除頭節點

   poll() 獲取頭節點的元素值,並刪除頭節點

 pop() 獲取頭節點的元素值,並刪除頭節點,頭節點為空則拋出異常

 1     /**
 2      * 獲取頭節點的元素值,但不刪除頭節點
 3      *
 4      */
 5     public E peek() {
 6         final Node<E> f = first;
 7         return (f == null) ? null : f.item;
 8     }
 9 
10  /**
11      * 獲取頭節點的元素值,並刪除頭節點
12      */
13     public E poll() {
14         final Node<E> f = first;
15         return (f == null) ? null : unlinkFirst(f);
16     }
17 
18  /**
19      * 刪除頭節點
20      */
21     private E unlinkFirst(Node<E> f) {
22         //獲取節點的值
23         final E element = f.item;
24         //獲取到后置節點
25         final Node<E> next = f.next;
26         //清空節點的值和后置節點
27         f.item = null;
28         f.next = null;
29         //重新設置頭節點
30         first = next;
31         //判斷后置節點是否為null
32         if (next == null)
33             //說明只有這么一個節點,尾部節點設置null
34             last = null;
35         else
36             //已經設置為頭節點了,所以清空前置節點
37             next.prev = null;
38         //數量減1
39         size--;
40         modCount++;
41         return element;
42     }
43 
44 /**
45      * 獲取頭節點的元素值,並刪除頭節點
46      */
47     public E pop() {
48         return removeFirst();
49     }
50 
51  /**
52      * 刪除頭節點
53      */
54     public E removeFirst() {
55         final Node<E> f = first;
56         //頭節點為空則拋出異常
57         if (f == null)
58             throw new NoSuchElementException();
59         //刪除頭節點
60         return unlinkFirst(f);
61     }
View Code

9.offer(E e)  添加新元素到末尾

  push(E e) 添加新元素到頭節點

 1 /**
 2      * 添加新元素到尾部
 3      *
 4      * @param e 新元素
 5      */
 6     public boolean offer(E e) {
 7         return add(e);
 8     }
 9 
10 
11     /**
12      * 添加一個元素
13      *
14      * @param e 添加的元素
15      */
16     public boolean add(E e) {
17         //調用添加到末尾
18         linkLast(e);
19         return true;
20     }
21 
22   /**
23      * 添加一個元素到鏈表的尾部
24      */
25     void linkLast(E e) {
26         //獲取鏈表的尾部節點
27         final Node<E> l = last;
28         //創建新的節點,前置節點為last,后置節點為空
29         final Node<E> newNode = new Node<>(l, e, null);
30         //重新設置尾部節點
31         last = newNode;
32         //如果之前的尾部節點為空,說明之前沒有元素
33         if (l == null)
34             //設置頭節點也為空
35             first = newNode;
36         else
37             //如果之前的尾部節點不為空,則為之前的尾部節點追加后置節點
38             l.next = newNode;
39         //數量加一
40         size++;
41         modCount++;
42     }
43 
44 /**
45      * 添加新元素到頭節點
46      *
47      * @param e the element to push
48      * @since 1.6
49      */
50     public void push(E e) {
51         addFirst(e);
52     }
53 
54 
55     /**
56      * 添加元素到頭節點
57      *
58      * @param e 新增的元素
59      */
60     public void addFirst(E e) {
61         //添加元素到頭節點
62         linkFirst(e);
63     }
64 
65  /**
66      * 添加元素到頭節點
67      */
68     private void linkFirst(E e) {
69         //獲取當前的頭節點
70         final Node<E> f = first;
71         //創建新節點
72         final Node<E> newNode = new Node<>(null, e, f);
73         //設置新節點為頭節點
74         first = newNode;
75         //判斷頭節點是否為空
76         if (f == null)
77             //頭節點為空,說明之前沒有節點,新節點同時為尾部節點
78             last = newNode;
79         else
80             //頭節點不為空,則頭節點的前置節點指向新節點
81             f.prev = newNode;
82         //數量加一
83         size++;
84         modCount++;
85     }
View Code

 總結一下

1.LinkedList作為雙向鏈表,維護了頭尾節點,頭尾節點的插入比較方便,中間數據的插入需要遍歷查詢再做插入

2.查詢指定位置時,使用了一次二分,最多需要遍歷一半的節點


免責聲明!

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



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