链表---双向链表

双向链表

单向链表的缺点分析:

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 }

 

posted @ 2021-02-04 15:20  安逸的坐姿  阅读(108)  评论(0编辑  收藏  举报