双向链表的实现
需求
创建一个带头节点的双向链表,用来存储英雄的信息(排名编号、姓名、昵称),并可以实现增删改查的操作
分析及实现
分析
- 与单向链表不同的是,单向蓝标查找的方向只能是一个方向,而双向链表可以向前或向后查找。
- 单向链表不能进行自我删除,需要依靠辅助节点,找到待删除节点的下一个节点。而双向链表可以进行自我删除。
实现
- 首先创建一个HeroNode类,里面包含两个部分data:no,name,nickName)以及next节点和pre节点
/**
* 定义一个英雄类
* 每个HeroNode就是一个节点
*/
class HeroNode2{
public int no;// 英雄排名
public String name;// 英雄名
public String nickName;// 昵称
HeroNode2 next;// next节点
HeroNode2 pre; // 指向前一个节点
public HeroNode2(int no, String name, String nickName){
this.no = no;
this.name = name;
this.nickName = nickName;
}
/**
* 重写toString方法
* @return
*/
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
}
- 添加
方式一:添加节点到最后
public void addHero(HeroNode2 newHeroNode){
HeroNode2 temp = head;// 辅助变量
while(temp.next != null){
temp = temp.next;
}
// 循环结束时,temp已经到达链表最后
temp.next = newHeroNode;
newHeroNode.pre = temp;
}
方式二:按照英雄的排名顺序添加
.
/**
* 按编号添加英雄
*/
public void addHeroByOrder(HeroNode2 heroNode2){
HeroNode2 temp = head;// 辅助变量
boolean flag = false;// 标识是否添加的了相同编号的英雄
while(true){
if(temp.next == null){
break;
}else if(temp.next.no > heroNode2.no){
break;
}else if(temp.next.no == heroNode2.no){
flag = true;
break;
}
temp = temp.next;
}
// 当排名重复时 不允许添加
if(flag){
System.out.println("添加的" + heroNode2.no + "号的英雄已经存在,不能重复添加!");
}
heroNode2.next = temp.next;
temp.next = heroNode2;
temp.next.pre = heroNode2;
heroNode2.pre = temp;
}
- 修改
/**
* 修改双向链表
* @param heroNode2
*/
public void updateHero(HeroNode2 heroNode2){
// 判断链表是否为空
if(head.next == null){
System.out.println("链表为空!");
}
HeroNode2 temp = head.next;
boolean flag = false; // 用来标识是否找到了指定编号的英雄
while(temp != null){
if(temp.no == heroNode2.no){// 若找到了该编号的英雄直接退出循环
flag = true;
break;
}
temp = temp.next;
}
if(flag){
temp.name = heroNode2.name;
temp.nickName = heroNode2.nickName;
}else{// 为找到节点
System.out.println("未找到编号为:" + heroNode2.no + "的英雄!");
}
}
- 删除
/**
* 删除双向链表的节点
* @param no
*/
public void delHero(int no){
// 判断链表为空
if(head.next == null){
System.out.println("链表为空!");
}
// 辅助变量
HeroNode2 temp = head.next;
boolean flag = false;
while(temp != null){
// 因为双向链表可以删除自身 所以直接使用temp.no = no
// 而单向链表不能删除自身 所以需要找到待删除节点的下一个节点 temp.next.no = no
if(temp.no == no){
flag = true;
break;
}
temp = temp.next;
}
if(flag){
// 找到了待删除的节点
// 将temp的前一个节点指向temp的下一个节点
temp.pre.next = temp.next;
// 将temp的下一个节点指向temp的前一个节点
// 但是这里可能会出现空指针异常
// 如果删除的是最后一个节点那么 temp.next为空 temp.next.no就会出现空指针异常
// 所以需要加一个判断
if(temp.next != null){
temp.next.pre = temp.pre;
}
}else{
System.out.println("未找到编号为:" + no + "的英雄!");
}
}
- 遍历
/**
* 遍历双向链表和遍历单向链表相同
*/
public void showList(){
// 首先判断链表是否为空
if(head.next == null){
System.out.println("链表为空!");
return ;
}
// 用一个临时节点来遍历链表
HeroNode2 temp = head.next;
while(true){
if(temp == null){
break;
}
System.out.println(temp.toString());
temp = temp.next;
}
}