1. 程式人生 > >Java學習筆記——淺談數據結構與Java集合框架(第一篇、List)

Java學習筆記——淺談數據結構與Java集合框架(第一篇、List)

技術分享 emp 鏈表 adc 下標 -c nod nal integer

橫看成嶺側成峰,遠近高低各不同。
不識廬山真面目,只緣身在此山中。

              ——蘇軾

這一塊兒學的是雲裏霧裏,咱們先從簡單的入手。逐漸的撥開迷霧見太陽。本次先做List集合的三個實現類的學習筆記

List特點:有序,元素可重復。其實它的本質就是一個線性表(下面會說到)

先上圖,Java集合有Collection體系和Map體系:

技術分享

然後簡單介紹一下數據結構和算法:

數據結構就是數據和數據之間的關系,好比分子結構,晶體結構。碳原子按照一定的方式組合在一起形成碳分子,碳分子再按照一定方式形成晶體。

算法是對解題步驟的描述,體現在計算機上就是指令的有限序列

數據結構分為邏輯結構和物理結構。

邏輯結構:

技術分享

物理結構:

順序存儲結構和鏈式存儲結構。

順序存儲結構:在內存中開辟若幹的連續空間,將每個空間存入數據,數據關聯與其地址一致。比如數組。

上代碼:

技術分享
 1 public class Test01 {
 2 
 3     public static void main(String[] args) {
 4         Integer[] arr = new Integer[10];
 5         //向數組中插入元素
 6         for (int i = 0; i < arr.length; i++) {
 7             arr[i] = i;
8 } 9 //將其中一個元素變為null; 10 arr[3] = null; 11 //出現碎片 12 for (Integer item : arr) { 13 System.out.println(item); 14 } 15 System.out.println("==========="); 16 arr[3] = 12;//存取方便,可直接賦值或取值 17 //刪除第X個元素,但要避免碎片產生: 18 int x = 2
; 19 arr[x-1]=null;//第二個元素引用變為null,該步驟可以省略,因為下面又更改了arr[x-1]的引用。寫上僅為便於理解 20 //第X個元素之後的元素前移,代碼表現為把後面的值依次賦給前面,從第X個開始 21 for (int i = x-1; i < arr.length-1; i++) { 22 arr[i] = arr[i+1]; 23 } 24 //length-1,需要新建數組來保存原數組 25 Integer[] newArr = new Integer[arr.length-1]; 26 for (int i = 0; i < newArr.length; i++) { 27 newArr[i]=arr[i]; 28 System.out.println(newArr[i]); 29 } 30 System.out.println("============"); 31 //第Y個位置插入一個元素 32 int y = 5; 33 //需要後移,所以先創建數組length+1 34 Integer [] newArr2 = new Integer[newArr.length+1]; 35 for (int i = 0; i < newArr.length; i++) { 36 newArr2[i] = newArr[i]; 37 } 38 //後移 39 for (int i = newArr2.length-1; i > y-1 ; i--) { 40 newArr2[i]=newArr2[i-1]; 41 } 42 //插入 43 newArr2[y-1] = 22; 44 //遍歷輸出 45 for (int i = 0; i < newArr2.length; i++) { 46 System.out.println(newArr2[i]); 47 } 48 } 49 50 }
View Code

出結論:

順序存儲結構:

優點:1無需為表示表中元素之間的邏輯關系而添加空間

   2可以快速地存取表中任意位置的元素

缺點:1插入和刪除操作需要移動大量元素

   2需要考慮索引越界為題

   3擴容空間可能會造成空間浪費,縮小空間又可能會索引越界

   4null值會造成空間“碎片”

鏈式存儲結構:每個元素只記住它下一個元素是誰(地址)。

鏈式存儲結構有多種,這裏只介紹Java的鏈式存儲結構:雙向鏈表

上代碼:

技術分享
 1 public class MyLinkedListDemo {
 2 
 3     public static void main(String[] args) throws Exception {
 4         MyLinkList<String> list = new MyLinkList<>();
 5         list.addFist("張三");
 6         list.addFist("李四");
 7         list.addLast("張三");
 8         list.addLast("李四");
 9         list.print();
10         System.out.println("===========");
11         list.add(2,"王五");
12         list.print();
13         System.out.println("===========");
14         list.add(5,"王五");
15         System.out.println(list.getSize());
16         list.add(7,"王五");//這裏會拋出空指針異常
17     }
18 }
View Code 技術分享
 1 public class MyLinkList<E> {
 2 
 3     Node<E> first;
 4     Node<E> last;
 5     
 6     public void addFist(E e){
 7         if (first == null) {
 8             final Node<E> newNode = new Node<E>(null, e, null);//第一次加入數據,為first,last賦初值
 9             first = newNode;
10             last = newNode;
11         }else{//否則把first的prev指向newNode,把newNode的next指向first,最後把newNode變為first
12             final Node<E> newNode = new Node<E>(null, e, first);
13             first.prev = newNode;
14             first = newNode;
15         }
16     }
17     public void addLast(E e){
18         if (last == null) {
19             final Node<E> newNode = new Node<E>(null, e, null);//第一次加入數據,為first,last賦初值
20             first = newNode;
21             last = newNode;
22         }else{//否則把last的next指向newNode,把newNode的prev指向last,最後把newNode變為last
23             final Node<E> newNode = new Node<E>(last, e, null);
24             last.next = newNode;
25             last = newNode;
26         }
27     }
28     public void add (int index,E e) throws Exception{//下標超出鏈表長度會空指針,因為超出長度的部分prev和next都是null
29         if(index == 0){
30             addFist(e);
31         }else if (index == getSize()) {
32             addLast(e);
33         }else {
34             //這裏畫張圖想一下,我要在1處插入x,就要把x的prev指向0,next指向1,把0的next指向x,把1的prev指向x
35             //這裏的1和0就是index和index-1,通過循環Node.next獲取index對應的Node
36             //先拿到0和1
37             Node<E> tempNodeNext = first;
38             for (int i = 0; i < index; i++) {
39                 tempNodeNext = tempNodeNext.next;
40             }
41             Node<E> tempNodePrev = tempNodeNext.prev;
42             //這裏改指向
43             final Node<E> newNode = new Node<E>(tempNodePrev, e, tempNodeNext);
44             tempNodeNext.prev = newNode;
45             tempNodePrev.next = newNode;
46         }
47     }
48     public int getSize (){
49         Node<E> temp = first;
50         int i = 0;
51         while(temp != null){
52             temp = temp.next;
53             i++;
54         }
55         return i;
56     }
57     //由於不實現Iterable,只能提供打印方法
58     public void print() {
59         Node<E> temp = first;
60         while(temp != null){
61             System.out.println(temp.item);
62             temp = temp.next;
63         }
64     }
65     private static class Node<E>{
66         Node<E> prev;
67         E item;
68         Node<E> next;
69         Node(Node<E> prev, E item, Node<E> next) {
70             super();
71             this.prev = prev;
72             this.item = item;
73             this.next = next;
74         }
75     }
76 }
View Code

出結論:

鏈式存儲結構:

優點:插入和刪除操作只需改變節點next和prev成員的指向即可,無需移位,無需擴容

缺點:失去了直接存取表中任意位置元素的能力

順序存儲結構和鏈式存儲結構的對比:

1、存儲分配方式:

順序存儲結構使用一段連續的存儲單元依次存儲線性表元素

鏈式存儲結構使用任意存儲單元存放線性表的元素

2、時間性能:

查找:

順序存儲結構O(1)

鏈式存儲結構O(n)

插入和刪除:

順序存儲結構O(n)

鏈式存儲結構O(1)

3、空間性能:

順序存儲結構:空間分大了浪費,分小了上溢,還得擴容

鏈式存儲結構:有空間就能分配,元素個數不受限制

言歸正傳。

ArrayList是順序存儲的線性表,LinkedList是鏈式存儲的線性表

它們的特點都是有序,元素值可以重復。區別是底層算法不同。

Vector,這裏我簡單瀏覽了一下源代碼,Vector底層算法和ArrayList是一樣的

這裏就不贅述了,直接說區別:

1、Vector的方法都是同步的(Synchronized),是線程安全的(thread-safe),而ArrayList的方法線程不安全,由於線程的同步必然要影響性能,因此ArrayList的性能比Vector好。
2、Vector擴容時容量翻倍,而ArrayList只增加50%的大小,(直接查它們的grow()方法)這樣,ArrayList就有利於節約內存空間。

總之ArrayList比Vector在性能方面(無論時間性能還是空間性能)都是能省則省。

List就說到這裏。下一篇說說隊列

Java學習筆記——淺談數據結構與Java集合框架(第一篇、List)