双向链表原理及应用举例
双向链表
双向链表也叫双链表,是链表的一种,它的每个数据节点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
图示1:
图示2:
分析:
1.遍历与修改实现方式与单链表一致
2.添加(默认添加到双向链表最后)
(1)先找到双向链表的最后一个节点
(2)temp.next=HeroNode2; //对本例的条件
(3)HeroNode2.pre=temp;
3.删除
(1)因为是双向链表,我们可以实现自我删除某个节点,直接找到我们要删除的节点,比如temp
(2)temp.pre.next=temp.next; //对本例的条件
(3)temp.next.pre=temp.pre;
应用举例
使用带head头节点的双向链表实现水浒英雄排行榜
代码
package com.atxihua; public class DoubleLinkedListDemo { public static void main(String[] args) { System.out.println("双向链表测试"); //创建节点 HeroNode2 hero4=new HeroNode2(4,"林冲","豹子头"); HeroNode2 hero3=new HeroNode2(3,"吴用","智多星"); HeroNode2 hero2=new HeroNode2(2,"卢俊义","玉麒麟"); HeroNode2 hero1=new HeroNode2(1,"宋江","及时雨"); //创建一个双向链表 DoubleLinkedList doubleLinkedList=new DoubleLinkedList(); doubleLinkedList.add(hero1); doubleLinkedList.add(hero2); doubleLinkedList.add(hero3); doubleLinkedList.add(hero4); doubleLinkedList.list(); //修改 HeroNode2 newHeroNode=new HeroNode2(4,"公孙胜","入云龙"); doubleLinkedList.update(newHeroNode); System.out.println("修改后的双向链表"); doubleLinkedList.list(); //删除 doubleLinkedList.del(3); System.out.println("链表删除后的情况"); doubleLinkedList.list(); } } class HeroNode2{ public int no; public String name; public String nickname; public HeroNode2 next;//指向下一个节点,默认为null public HeroNode2 pre;//指向前一个节点,默认为null //构造器 public HeroNode2(int no, String name, String nickname) { this.no = no; this.name = name; this.nickname = nickname; } //为了显示方便,重新toString @Override public String toString() { return "HeroNode2{" + "no=" + no + ", name='" + name + '\'' + ", nickname='" + nickname + '\'' + '}'; } } //创建一个双向链表的类 class DoubleLinkedList{ //先初始化一个头节点,头节点不要动,不存放具体的数据 private HeroNode2 head=new HeroNode2(0,"",""); //返回头节点 public HeroNode2 getHead() { return head; } //遍历双向链表 public void list(){ //判空 if(head.next==null){ System.out.println("链表为空"); return; } //因为头节点不能动,因此我们需要一个辅助变量来遍历 HeroNode2 temp=head.next; while (true){ //判断是否到链表最后 if(temp==null){ break; } //输出节点信息 System.out.println(temp); //将temp后移 temp=temp.next; } } //添加一个节点到双向链表最后 public void add(HeroNode2 HeroNode2){ //因为头节点不能动,因此我们需要一个辅助变量来遍历 HeroNode2 temp=head; while (true){ //判断是否到链表最后 if(temp.next==null){ break; } //如果未找到将temp后移 temp=temp.next; } //当退出while循环时,temp就指向了链表的最后 //形成了一个双向链表 temp.next=HeroNode2; HeroNode2.pre=temp; } //修改一个节点的内容,与单链表修改相同 public void update(HeroNode2 newHeroNode2){ //判空 if(head.next==null){ System.out.println("链表为空"); return; } //定义一个辅助节点 HeroNode2 temp=head.next; boolean flag=false;//表示是否找到该节点 while (true){ if(temp==null){ break;//已经遍历完链表 } if(temp.no==newHeroNode2.no){ //找到该节点 flag=true; break; } //未找到,后移 temp=temp.next; } if(flag){ temp.name= newHeroNode2.name; temp.nickname= newHeroNode2.nickname; }else{ System.err.println("该英雄不存在!!!请检查输入排名是否正确"); } } /* 从双向链表中删除一个节点 * 说明 * 1.对于双向链表,我们可以直接找到要删除的这个节点 * 2.找到后,自我删除即可 * */ public void del(int no){ //判空 if(head.next==null){ System.out.println("链表为空,无法删除"); return; } HeroNode2 temp=head.next;//辅助变量 boolean flag=false;//标志是否找到删除的节点 while (true){ if(temp==null){ //已到链表的最后 break; } if(temp.no==no){ flag=true; break; } temp=temp.next;//temp后移,遍历 } if(flag){ temp.pre.next=temp.next; //如果是最后一个节点,就不需要执行下面这句话,否则会出现空指针 if(temp.next!=null){ temp.next.pre=temp.pre; } }else{ System.out.println("要删除的节点并不存在"); } } }
运行结果:
为了更好的看到双向链表的数据结构,我们直接来看新增之后doubleLinkedList里的数据
可以看到数据结构与双向链表图示1完全一致。