文章目录
前言
对于单向链表来说,查找的方向只能单向的,所以进行删除或插入,我们需要找到目标的前一个结点(无法实现向后查找的弊端)。
单向链表不能自我删除,借助辅助节点才可以,双向链表则可以查看前驱节点,从而实现自我删除,介绍如下:
一、双向链表的介绍:
1. 见名知义,双向链表可以向前或向后查找;
2. 双向链表删除节点,只需要找到删除的目标节点自身即可;
3. 双向链表插入节点,只要找到插入的位置本身就可以;
4. 所以,双向链表很方便,不需要借助与其他节点就可以实现很多功能;
二、相关操作
1. 新建双向链表的类
显然,双向链表需要保存它的前驱节点的信息,因此比单向链表的属性会多一个;
代码如下:
class HeroNode2{
public int no; //编号
public String name;·//姓名
public String nickname;//绰号
public HeroNode2 next;//下个节点域
public HeroNode2 per;//前驱节点域
//构造器
public HeroNode2(int n , String name , String nickname){
this.no = n;
this.name = name;
this.nickname = nickname;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickname='" + nickname + '\'' +
'}';
}
}
2.删除数据(变化较大,有坑🔺)
1. 因为是双向链表,所以可以实现自我删除节点
2. 直接找到要删除的节点,例如为p
3. p.pre.next = p.next;
4. temp.next.pre = temp.pre;
相当于p前里面和后面的节点把p节点给覆盖掉了:
代码如下:
public void delate(int no){
if(head.next == null){
System.out.println("链表为空,删除失败....");
return;
}
boolean flag = false;//是否找到待删除结点
HeroNode2 p = head.next;
while(true){
if(p == null){
break;
}
if(p.no == no){
flag = true;
break;
}
p = p.next;
}
if(flag){
p.per.next = p.next;
//这里的代码需要注意(如果删除的是最后一个节点.就不需要最后一句话,否则空指针异常)
if(p.next != null)//待删除的节点不是最后一个才能进行这步
p.next.per = p.per;
return;
}else{
System.out.println("删除失败,未找到...");
return;
}
}
3. 中间添加数据
1. 找到要添加的位置p
2. newNode.next = p;
3. p.pre.next = newNode;
4. newNode.pre = p.pre;
5. p.pre = newNode;
按照这个顺序,不能先断开p.pre否则会出错
代码如下:
4.尾部添加数据(稍微变化)
默认尾部添加数据
1. 先找到双向链表的最后;
2. temp.next = newHeroNode
3. newHeroNode.pre = temp:实现双向链表
代码如下:
public void add(HeroNode2 heroNode){
//因为head节点不能动,保护原链表
HeroNode2 temp = head;
//遍历到最后
while(temp.next != null){
temp = temp.next;
}
//形成一个双向链表
temp.next = heroNode;
heroNode.per = temp;
}
5.修改数据(思路不变)
根据编号修改,所以编号不可以变
1. 判断双链表是否为空,为空处理即可
2. 链表不为空,则遍历查找到编号对应的节点即可
3. 找到之后更新节点信息即可
代码如下:
public void update(HeroNode2 newHeroNode){
if(head.next == null){
System.out.println("链表为空");
return;
}
HeroNode2 p = head.next;
boolean flag = false;
while(true){
if(p.no == newHeroNode.no){
flag = true;
break;
}
if(p == null){
break;
}
p = p.next;
}
if(flag){
p.name = newHeroNode.name;
p.nickname = newHeroNode.nickname;
}else{
System.out.println("未找到要修改的英雄,请重试");
return;
}
}
6.双向链表的遍历(无变化)
1. 遍历的方式和单链表相同:
2. 可以双向遍历(向前或向后遍历)
代码如下:
public void show(){
if(head.next == null){
System.out.println("链表为空");
return;
}
HeroNode2 temp = head.next;
while(true){
if(temp == null){
break;
}
System.out.println(temp);
temp = temp.next;
}
}
总结
1. 删除和添加节点的时候仅需找到要删除或者添加的位置即可,不需要找到前面一个;2. 删除结点的时候应注意是否是最后一个节点,最后一个节点注意避坑;
3. 注意在中间节点添加数据的操作顺序;