数据结构--链表

时间:2020-04-16
本文章向大家介绍数据结构--链表,主要包括数据结构--链表使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一、链表

  (一)链表介绍 

    1) 链表是有序存储,节点的方式来存储是链式存储结构
    2) 每个节点包含 data 域(用来存储数据), next 域: 指向下一个节点(next中存储了要指向节点的内存地址)
    3) 如图: 链表的各个节点不一定是连续存储.
    4) 链表分带头节点的链表和没有头节点的链表, 根据实际的需求来确定 。头结点是指data域为空的节点,只有指向下一个节点的next域。

      链表在内存中的存储形式:                                                                              链表的逻辑形式:

                 

  (二)单向链表的应用

      在以下应用中,涉及到对链表的遍历时,需要将头结点赋值给一个辅助节点temp(因为头结点不能动),使用temp=temp.next来后移节点

      1、向链表中添加节点。分为两种情况:

        1)按添加语句的输入顺序添加节点:直接将节点添加到链表尾部。只需要使链表尾节点的next指向要添加的节点即可

    

     代码实现如下

 1     /**
 2      * 将新节点加入链表
 3      * 当不考虑编号时
 4      *      思路:1、遍历链表,找到next=null的尾节点
 5      *          2、将尾节点的next指向新节点
 6       * @param heroNode  需要添加的新节点
 7      */
 8     public void addNode(HeroNode heroNode){
 9         //遍历链表,找到结尾,在结尾处加入新的节点
10         HeroNode temp=headNode;//头结点不能动,需要辅助变量来遍历
11         while (true){
12             if (temp.next == null) {
13                 break;
14             }
15             //将节点后移
16             temp=temp.next;
17         }
18         //将新节点加到尾部
19         temp.next=heroNode;
20     }

     2)按节点中的数据顺序添加节点:需要按照编号的顺序进行添加。

      思路:遍历链表,将本节点的下个节点的编号(no1)(因为单向链表只有一个指向下个节点的next,无法指向上一个节点)与要添加节点的编号(no2)进行比较,

  若no1>no2(按升序进行添加)则添加。

         添加方式:新节点.next=temp.next

              temp.next=新节点

       代码实现如下:

 1     /**
 2      第二种方式在添加英雄时,根据排名将英雄插入到指定位置(如果有这个排名, 则添加失败, 并给出提示
 3      * @param heroNode
 4      */
 5     public void addNodeSort(HeroNode heroNode){
 6         //对链表进行遍历
 7         HeroNode temp=headNode;
 8         boolean flag=false;
 9         while (true){
10             if (temp.next == null) {
11                 break;
12             }
13 //如果有这个排名, 则添加失败, 并给出提示
14             if (temp.next.no==heroNode.no){
15                flag=true;
16                break;
17             }
18             if ( heroNode.no<temp.next.no){
19                 break;
20             }
21             temp=temp.next;
22         }
23         if (flag){
24             System.out.printf("已有此编号%d,无法加入\n",heroNode.no);
25         }else {
26             heroNode.next=temp.next;
27             temp.next=heroNode;
28         }
29     }

    

    2、删除节点

        若当前节点的next指向的节点为要删除的节点,则执行

          //使当前节点的next指向下下个节点,完成对下个节点的删除  temp.next=temp.next.next;  

          

      代码实现如下:

 1     /**
 2      * 根据no删除节点
 3      */
 4     public void deleteNode(int no){
 5         HeroNode temp=headNode;
 6         boolean flag=false;
 7         if (temp.next==null){
 8             return;
 9         }
10         while (true){
11             //已经到达尾节点,跳出循环
12             if (temp.next == null) {
13                 break;
14             }
15             //如果当前节点的next指向的下个节点为要删除的节点
16             if (no==temp.next.no){
17                 flag=true;
18                 break;
19             }
20             temp=temp.next;
21         }
22         if (flag){
23             //使当前节点的next指向下下个节点,完成对下个节点的删除
24             temp.next=temp.next.next;
25         }else {
26             throw new RuntimeException("该节点不存在");
27         }
28     }

     3、遍历链表

      代码实现如下

 1     /**
 2      * 遍历链表
 3      */
 4     public void showLists(){
 5         //先判断链表是否为空
 6         if (headNode.next == null) {
 7             System.out.println("链表为空");
 8             return;
 9         }
10         HeroNode temp=headNode.next;//
11         while (true){
12             //当前节点为链表尾
13             if (temp== null) {
14                 break;
15             }
16             //输出当前节点的信息
17             System.out.println(temp);
18             //节点后移
19             temp=temp.next;
20         }
21     }

   (三)双向链表的应用

      管理单向链表的缺点分析:

  • 1) 单向链表, 查找的方向只能是一个方向, 而双向链表可以向前或者向后查找。
  • 2) 单向链表不能自我删除, 需要靠辅助节点 , 而双向链表, 则可以自我删除。

     双向链表中的节点由三部分构成:pre域(指向上一个节点的内存地址)+data域(存储数据)+next域(指向下一个节点的内存地址)。

  

    单双向列表应用的差异主要体现在删除节点上

        //完成对当前节点的删除

        temp1.pre.next=temp1.next;

        //当前节点为尾节点时,不能执行下句,否则会出现空指针异常

        if (temp1.next!=null) { temp1.next.pre = temp1.pre;}

 1     /**
 2      * 根据no删除节点
 3      * 双向链表可以实现当前节点的自我删除,不需要通过上一个节点删除
 4      */
 5     public void deleteNode(int no){
 6         HeroNode1 temp1=headNode1.next;
 7         boolean flag=false;
 8         if (temp1==null){
 9             return;
10         }
11         while (true){
12             if (temp1 == null) {
13                 break;//temp节点为尾节点
14             }
15             //如果当前节点为要删除的节点
16             if (no==temp1.no){
17                 flag=true;
18                 break;
19             }
20             temp1=temp1.next;//当前节点temp为尾节点时,则有temp=temp.next==null,所以下次循环时会退出循环
21         }
22         if (flag){
23             //完成对当前节点的删除
24             temp1.pre.next=temp1.next;
25             //当前节点为尾节点时,不能执行下句,否则会出现空指针异常
26             if (temp1.next!=null) {
27                 temp1.next.pre = temp1.pre;
28             }
29 
30         }else {
31             throw new RuntimeException("该节点不存在");
32         }
33     }

      

      

原文地址:https://www.cnblogs.com/Cong-l/p/12715225.html