• 链表---双向链表


    双向链表

    单向链表的缺点分析:

    1) 单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找。

    2) 单向链表不能自我删除,需要靠辅助节点 ,而双向链表,则可以自我删除,所以前面我们单链表删除 时节点,总是找到 temp,temp 是待删除节点的前一个节点(认真体会).

    对上图的说明

    分析 双向链表的遍历,添加,修改,删除的操作思路===》代码实现

    1) 遍历  单链表一样,只是可以向前,也可以向后查找

    2) 添加 (默认添加到双向链表的最后) 

      (1) 先找到双向链表的最后这个节点

      (2) temp.next = newHeroNode

      (3) newHeroNode.pre = temp; 

     添加:添加到链表中间去

      如图:

      

    3) 修改 思路和 原来的单向链表一样

    4) 删除

      (1) 因为是双向链表,因此,我们可以实现自我删除某个节点

      (2) 直接找到要删除的这个节点,比如 temp

      (3) temp.pre.next = temp.next;

      (4) temp.next.pre = temp.pre;

    双向链表的应用实例

    使用带 head 头的双向链表实现 –水浒英雄排行榜

    代码实现:

      1 package com.hut.linkedlist.test2;
      2 
      3 import com.hut.linkedlist.test2.HeroNode;
      4 
      5 /*
      6  * 使用带 head 头的双向链表实现 –水浒英雄排行榜
      7  * */
      8 
      9 public class DoubleLinkedListDemo {
     10 
     11     public static void main(String[] args) {
     12         // 进行测试
     13         // 先创建节点
     14         HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
     15         HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
     16         HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
     17         HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
     18 
     19         // 创建要给的链表
     20         DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
     21 /*    //测试添加节点到末尾    
     22         //添加节点到末尾
     23         doubleLinkedList.add(hero1);
     24         doubleLinkedList.add(hero2);
     25         doubleLinkedList.add(hero3);
     26         doubleLinkedList.add(hero4);
     27         //显示添加后的双向链表
     28         doubleLinkedList.list();
     29 */    
     30         //测试根据编号插入节点
     31         doubleLinkedList.add(hero1);
     32         doubleLinkedList.add(hero2);
     33         doubleLinkedList.add(hero4);
     34         System.out.println("插入前链表显示情况:");
     35         doubleLinkedList.list();
     36         doubleLinkedList.addByOrder(hero3);
     37         System.out.println("插入后链表显示情况:");
     38         doubleLinkedList.list();
     39         
     40     //测试修改节点
     41         System.out.println("=========================================");
     42         System.out.println("修改前的链表显示:");
     43         doubleLinkedList.list();
     44         doubleLinkedList.update(new HeroNode(4,"废林冲","受气包"));
     45         System.out.println("修改后的链表显示:");
     46         doubleLinkedList.list();
     47         
     48         //测试删除节点
     49         System.out.println("=========================================");
     50         System.out.println("删除前的链表显示:");
     51         doubleLinkedList.list();
     52         doubleLinkedList.del(4);
     53         System.out.println("修改后的链表显示:");
     54         doubleLinkedList.list();
     55 
     56     }
     57 
     58 }
     59 
     60 //定义单链表DoubleLinkedList 管理英雄
     61 class DoubleLinkedList {
     62     // 先初始化一个头节点, 头节点不要动, 不存放具体的数据
     63     private HeroNode head = new HeroNode(0, "", "");
     64 
     65     public HeroNode getHead() {
     66         return head;
     67     }
     68 
     69     public void setHead(HeroNode head) {
     70         this.head = head;
     71     }
     72 
     73     //功能一、 添加一个节点到双向链表的最后
     74     public void add(HeroNode newHeroNode) {
     75         //因为head节点不能动,所以需要一个辅助变量temp来遍历链表
     76         HeroNode temp = head;
     77         //遍历双向链表,找到末尾
     78         while(true) {
     79             if(temp.next == null) {
     80                 break;
     81             }
     82             //如果没有找到则后移
     83             temp = temp.next;
     84         }
     85         //当退出while循环时,temp就指到了最后
     86         temp.next = newHeroNode;
     87         newHeroNode.pre = temp;
     88     }
     89     
     90     //功能二、按照编号 no 添加节点到双向链表中去
     91     public void addByOrder(HeroNode newHeroNode) {
     92         //定义一个辅助变量temp来帮助遍历链表
     93         HeroNode temp = head.next;
     94         boolean flag = false;  //标志编号是否已经存在
     95         while(true) {
     96             if(temp == null) {
     97                 break;  //已经遍历结束
     98             }
     99             if(temp.no > newHeroNode.no) {
    100                 break;  //位置已经找到
    101             } 
    102             if(temp.no == newHeroNode.no) {
    103                 flag = true;
    104                 break;
    105             }
    106             temp = temp.next;
    107         }
    108         //根据flag值的情况来判断
    109         if(flag) {
    110             System.out.printf("编号为%d的节点已经存在,不能再次插入~~",newHeroNode.no);
    111         }else {
    112             //核心操作
    113             temp.pre.next = newHeroNode;
    114             newHeroNode.pre = temp.pre;
    115             newHeroNode.next = temp;
    116             temp.pre = newHeroNode;
    117         }
    118         
    119     }
    120 
    121     // 功能三、修改一个节点的内容, 可以看到双向链表的节点内容修改和单向链表一样
    122     public void update(HeroNode newHeroNode) {
    123         //判断双向链表是否为空
    124         if(head.next == null) {
    125             System.out.println("双向链表为空,无法修改~~");
    126             return;
    127         }
    128         //根据编号no找到要修改的节点
    129         HeroNode temp = head.next;
    130         boolean flag = false;//标志是否找到该节点
    131         while(true) {
    132             if(temp == null) {
    133                 break;   //已经遍历完链表
    134             }
    135             if(temp.no == newHeroNode.no) {
    136                 flag = true;
    137                 break;
    138             }
    139             temp = temp.next;
    140         }
    141         //当while循环结束后,就会找到要修改的节点
    142         if(flag) {
    143             temp.name = newHeroNode.name;
    144             temp.nickname = newHeroNode.nickname;
    145         }else {
    146             System.out.printf("没有找到编号为%d的节点,无法修改~~",newHeroNode.no);
    147         }
    148     }
    149     
    150     // 功能四、从双向链表中删除一个节点
    151             //根据编号 no来删除
    152     public void del(int no) {
    153         //判断链表是否为空
    154         if(head.next == null) {
    155             System.out.println("双向链表为空,无法删除~~");
    156             return;
    157         }
    158         HeroNode temp = head.next;
    159         boolean flag = false;//标志是否找到要删除的节点
    160         while(true) {
    161             if(temp == null) {
    162                 break;  //链表遍历完毕
    163             }
    164             if(temp.no == no) {
    165                 flag = true;
    166                 break;
    167             }
    168             temp = temp.next;
    169         }
    170         //当遍历完毕就会找到要删除的节点
    171         if(flag) {
    172             temp.pre.next = temp.next;
    173             // 如果是最后一个节点,就不需要执行下面这句话,否则出现空指针
    174             if(temp.next != null) {
    175             temp.next.pre = temp.pre;
    176             }
    177         }else {
    178             System.out.println("没有找到要被删除的该节点~~");
    179         }
    180     }
    181 
    182     //功能五、 遍历双向链表的方法
    183         // 显示双向链表【遍历】
    184     public void list() {
    185         //判断双向链表是否为空
    186         if(head.next == null) {
    187             System.out.println("双向链表为空~~");
    188             return;
    189         }
    190         //定义一个辅助变量来帮忙遍历双向链表
    191         HeroNode temp = head.next;
    192         while(true) {
    193             if(temp == null) {
    194                 break;
    195             }
    196             //输出节点信息
    197             System.out.println(temp);
    198             temp = temp.next;  //节点后移,一定要注意
    199         }
    200     }
    201 
    202 }
    203 
    204 //定义HeroNode节点,每个HeroNode对象就是一个节点
    205 class HeroNode {
    206     public int no; // 编号
    207     public String name; // 姓名
    208     public String nickname; // 绰号
    209     public HeroNode next; // 指向下一个节点
    210     public HeroNode pre; // 指向上一个节点
    211 
    212     // 构造器
    213     public HeroNode(int no, String name, String nickname) {
    214         this.no = no;
    215         this.name = name;
    216         this.nickname = nickname;
    217     }
    218 
    219     // 为了显示,重写toString方法
    220     @Override
    221     public String toString() {
    222         return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
    223     }
    224 
    225 }
  • 相关阅读:
    7-3色彩平衡
    Flex 布局
    JS获取当前周
    虚树学习笔记
    当然,perl等脚本服务器是一般默认安装了,你入侵了一台主机,总不能先装配 Java 环境然后再开干吧?
    还有这种书,程序开发心理学(豆瓣)
    Codeforces Round #143 (Div. 2)
    Codeforces Round #142 (Div. 2)
    Codeforces Round #141 (Div. 2)
    2018-2019-1 20189221 书籍速读 第 1 周
  • 原文地址:https://www.cnblogs.com/cleanlife/p/14372791.html
Copyright © 2020-2023  润新知