链表

概念介绍

  有同学想认识链表,今天它来!它存储数据不需要连续的内存空间,它扩展方便,大小可变,它于百万军中取敌将首级如探囊取物,也被称为“灵活一号”!

  链表家族的成员有3类,分别是单向链表,双向链表和循环链表。说一千,道一万,不如上图直接看。

  单向链表

     

   每个节点除了要存储自身数据外,还要存储下一节点的指向,通过每个节点的指向,把N个节点连成一个链表。单向链表大家可以记为:我中有你,你中无我。

1 class Node {
2     // 存储的数据
3     public Object data;
4     // 下一节点
5     public Node next;
6 }

  双向链表

  

   相对于单向链表的节点,双向链表的节点,需要多存储上一节点的指向。双链表就是名副其实的:我中有你,你中有我。

1 class Node {
2     // 存储的数据
3     public Object data;
4     // 下一节点
5     public Node next;
6     // 上一节点
7     public Node pre;
8 }

  循环链表

  

  最大的特点就是最后一个结点的指针指向头结点,整个链表形成一个环。

代码实现

  在这里,我们实现的是双向链表,其实只要会一种,其他的都很好理解。我们只完成删除和添加节点的操作,修改就不实现了。

  我们先把节点定义出来,简单的定义,每个节点存储的是自己的名称。

 1 class Node {
 2     // 当前节点名称
 3     public String name;
 4     // 上一节点
 5     public Node next;
 6     // 下一节点
 7     public Node previous;
 8 
 9     public Node(String name) {
10         this.name = name;
11     }
12 }

  在节点尾部添加节点代码实现说明:A-B-C三个节点,如果我们想在链表的末端添加D,那么我们需要做的事情有2件:

  一、遍历链表,找到链表的最后一个节点。

  二、对最后一个节点进行操作,把C的下一个节点指向新添加的节点D并且把D的上一个节点指向C

 1     public void add(Node addNode) {
 2         // 在这里,我们使用curNode来帮助我们记录当前遍历到的元素
 3         Node curNode = head;
 4         // 如果链表为空,则添加的元素变为头结点
 5         if (curNode == null) {
 6             head = addNode;
 7             return;
 8         }
 9         // 如果不为空,我们的目的是走到链表的末端,所以这里使用while循环
10         // 当退出while循环时,curNode则为链表的最末端
11         while (true) {
12             // 只有链表最末端节点的next为null
13             if (curNode.next == null) {
14                 break;
15             }
16             // 如果没有找到最后, 将将temp后移
17             curNode = curNode.next;
18         }
19         // 这里对链表的最后一个节点进行操作
20         curNode.next = addNode;
21         addNode.previous = curNode;
22     }

  在节点尾部添加节点代码实现说明:A-B-C三个节点,如果我们想把B节点删除掉,那么我们需要做的事情有3件:

  一、遍历链表,找到B节点。

  二、对B的上一个节点A节点进行操作,操作的动作为,将A的下一节点指向C。

  三、对B的下一个节点C节点进行操作,操作的动作为,将C的上一节点指向A。

 1     public void delete(Node delNode) {
 2         // 判断当前链表是否为空,如果为空,肯定无法杀出
 3         if (head == null) {
 4             System.out.println("链表为空,无法删除");
 5             return;
 6         }
 7         // 同样的,在这里,我们使用curNode来帮助我们记录当前遍历到的元素
 8         Node curNode = head;
 9         // 标志是否找到待删除的节点
10         boolean flag = false;
11         while (true) {
12             // 已经到链表的最后,这是退出while循环的一种情况
13             if (curNode == null) {
14                 break;
15             }
16             // 已经找到待删除的节点目标,可以退出while循环了
17             if (curNode.name.equals(delNode.name)) {
18                 flag = true;
19                 break;
20             }
21             curNode = curNode.next;
22         }
23         // 如果找到删除的目标节点,则进行以下操作
24         if (flag) {
25             // 所谓的删除,就是把找到的节点的前置节点的后置节点变为删除节点的后置节点
26             // 如果待删除的节点为第一节点
27             if(curNode.previous == null){
28                 if(curNode.next!=null){
29                     curNode.next.previous = null;
30                     head = curNode.next;
31                 }else {
32                     head = null;
33                 }
34                 return;
35             }
36             curNode.previous.next = curNode.next;
37             // 如果删除的目标节点是最后一个,则没有这步操作
38             if (curNode.next != null) {
39                 curNode.next.previous = curNode.previous;
40             }
41             return;
42         }
43         System.out.printf("要删除的 %s 节点不存在
", delNode.name);
44     }

    至此,代码编写完成,如果大家顺着思路去写下来,理解之后,那么再去看LinkedList的源码,会轻松不少,Git地址:https://github.com/HollowCup/algorithms-and-data-structure,具体实现位于data-structure工程下的linkedList目录,如果发现不足之处,请联系我进行更改,十分感谢!关注我,为你揭秘更多数据结构!

  

原文地址:https://www.cnblogs.com/maguanyue/p/11543305.html