01玩转数据结构_04_最基础的动态数据结构:链表

什么是链表:

我们之前已经学过了 动态数组,栈和 队列 三种我们自己定义的数据结构。它们三者的底层都是依托静态数组(使用resize解决容量问题)。

而下面我们学习的链表,它才是真正的动态数据结构

为什么链表很重要:

1,它是最简单的动态数据结构,有助于学习后面更加复杂的数据结构。

2,有助于更深入的理解引用 (Java) 指针(c/c++)。

3,   有助于更深入的理解递归。

4, 辅助组成其他数据结构。

链表基础:

数组 和 链表 的对比:

代码:

 1 package cn.zcb.demo04;
 2 
 3 public class LinkedList <T> {
 4     private class Node{
 5         public T data;//具体数据
 6         public Node next; //引用(指针)
 7 
 8         //Node 节点的构造器
 9         public Node(T data,Node next){
10             this.data  = data;
11             this.next = next;
12         }
13         public Node(T data){
14             this(data,null);
15         }
16         public  Node(){
17             this(null,null);
18         }
19 
20         @Override
21         public String toString(){
22             return this.data.toString();
23         }
24 
25     }
26 
27 
28 }
构建节点!!!

在链表中添加元素:

 1 package cn.zcb.demo04;
 2 
 3 public class LinkedList <T> {
 4     private class Node{
 5         public T data;//具体数据
 6         public Node next; //引用(指针)
 7 
 8         //Node 节点的构造器
 9         public Node(T data,Node next){
10             this.data  = data;
11             this.next = next;
12         }
13         public Node(T data){
14             this(data,null);
15         }
16         public  Node(){
17             this(null,null);
18         }
19 
20         @Override
21         public String toString(){
22             return this.data.toString();
23         }
24 
25     }
26 
27     private Node head; //头节点
28     private int size;
29     //LinkedList 的构造器
30 
31     public LinkedList (){  //只需要空参构造器  , Node() 实例化需在LinkedList 内部实现!!!外部无法实现。
32         this.head = null;
33         this.size = 0;
34     }
35     //获取链表中的元素个数
36     public int getSize(){
37         return this.size;
38     }
39     //返回链表是否为空
40     public boolean isEmpty(){
41         return this.size ==0;
42     }
43 
44     //在链表头添加 新的元素 newData
45     public void addFirst(T newData){
46 //        Node newNode = new Node(newData,null);
47 //
48 //        newNode.next = this.head;
49 //        this.head = newNode;
50         //下面是更简洁的写法
51         this.head = new Node(newData,this.head);   //一句话 顶上面三句话。
52         this.size ++;
53     }
54     //在链表 中间 索引(idx)  添加新元素
55     public void insertByIdx(int idx,T newData){
56         if(idx <= 0 || idx > this.size){
57             //在链表头插入
58             this.addFirst(newData);
59             return;
60         }
61         Node tempPtr = new Node();
62         tempPtr = this.head;
63         for (int i =0;i< idx -1 ;i++){
64             tempPtr = tempPtr.next;
65         }
66         Node node = new Node(newData,tempPtr.next);
67         tempPtr.next = node;
68 
69         this.size ++;
70     }
71 
72     //在链表尾部 添加新元素
73     public void addLast(T newData){
74         this.insertByIdx(this.size,newData);
75     }
76 
77     @Override
78     public String toString(){
79         StringBuilder builder = new StringBuilder();
80         builder.append(String.format("LinkList's Data is below: [size:%d] \n", this.size));
81         Node tempPtr = this.head;
82 
83         while (tempPtr !=null){
84             builder.append(tempPtr.data +", ");
85            tempPtr =tempPtr.next;
86         }
87         return builder.toString();
88     }
89 
90 }
在链表中添加元素(在链表头添加,在链表中添加,和在链表尾添加)

为链表设立虚拟头节点(重要):

在前面 在链表中添加元素的时候,我们会发现, 操作链表头节点和 操作其他的节点的时候的逻辑会不同。

这时因为,链表头节点的前面已经没有节点了。所以它和其他的节点会有区别。

这样头节点的处理逻辑 就和其他的节点一致了。 

 1 package cn.zcb.demo04;
 2 
 3 public class LinkedList <T> {
 4     private class Node{
 5         public T data;//具体数据
 6         public Node next; //引用(指针)
 7 
 8         //Node 节点的构造器
 9         public Node(T data,Node next){
10             this.data  = data;
11             this.next = next;
12         }
13         public Node(T data){
14             this(data,null);
15         }
16         public  Node(){
17             this(null,null);
18         }
19 
20         @Override
21         public String toString(){
22             return this.data.toString();
23         }
24 
25     }
26 
27     private Node dummyHead; //虚拟头节点
28     private int size;
29     //LinkedList 的构造器
30 
31     public LinkedList (){    //此时,当链表初始化的时候就已经存在一个 虚拟的头节点了。
32         dummyHead = new Node(null,null);
33         this.size = 0;
34     }
35     //获取链表中的元素个数
36     public int getSize(){
37         return this.size;
38     }
39     //返回链表是否为空
40     public boolean isEmpty(){
41         return this.size ==0;
42     }
43     //在链表 中间 索引(idx)  添加新元素
44     public void insertByIdx(int idx,T newData){
45         if(idx < 0 || idx > this.size){
46             throw new IllegalArgumentException("idx 错误!");
47         }
48         Node tempPtr = new Node();
49         tempPtr = this.dummyHead;
50         for (int i =0;i< idx;i++){
51             tempPtr = tempPtr.next;
52         }
53         Node node = new Node(newData,tempPtr.next);
54         tempPtr.next = node;
55 
56         this.size ++;
57     }
58 
59     //在链表头添加 新的元素 newData
60     public void addFirst(T newData){
61         insertByIdx(0,newData);
62     }
63     //在链表尾部 添加新元素
64     public void addLast(T newData){
65         this.insertByIdx(this.size,newData);
66     }
67 
68     @Override
69     public String toString(){
70         StringBuilder builder = new StringBuilder();
71         builder.append(String.format("LinkList's Data is below: [size:%d] \n", this.size));
72         Node tempPtr = this.dummyHead.next;
73 
74         while (tempPtr !=null){
75             builder.append(tempPtr.data +", ");
76            tempPtr =tempPtr.next;
77         }
78         return builder.toString();
79     }
80 
81 }
使用虚拟头节点,可以使得代码更加优雅!!!

注意:有了虚拟头节点,插入时的遍历就不是从真正的head 开始了,而是从虚拟头节点开始遍历。 注:查看时候的遍历是从真正的head 开始的。 

 1 package cn.zcb.demo04;
 2 
 3 public class Test {
 4 
 5     public static void main(String[] args) {
 6         LinkedList<Integer> linkedList = new LinkedList<>();
 7 //        for (int i =0;i<10;i++){
 8 //            linkedList.addFirst(i);
 9 //        }
10 
11 
12         linkedList.addLast(12);
13         linkedList.addLast(11);
14         for (int i=0;i<6;i++){
15             linkedList.addLast(i);
16         }
17         System.out.println(linkedList);
18 
19 
20         linkedList.addFirst(15);
21         linkedList.addFirst(15);
22         linkedList.addFirst(15);
23         linkedList.addFirst(15);
24         System.out.println(linkedList);
25         linkedList.addLast(12);
26         linkedList.addLast(12);
27         linkedList.addLast(12);
28         linkedList.addLast(12);
29         linkedList.addLast(12);
30         System.out.println(linkedList);
31         
32 
33 
34     }
35 
36 
37 
38 
39 }
Test.java

总结: 

虚拟头节点为 添加元素 统一了处理逻辑。这是很重要的一点!!!

在链表中 遍历 ,查询 和修改 元素:

猜你喜欢

转载自www.cnblogs.com/zach0812/p/11869180.html