开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情
双向链表
特点:
1>跟单链表相比,多了一个pre,可以指向前一个节点。
2>遍历方法跟单链表一样,但是可以向前查找,也可以向后查找
3>添加,默认是添加到双向链表的最后面
先找到双向链表的最后节点,在将next域更新的同时不要忘记pre域
temp.next=newHeroNode;
newHeroNode.pre=temp;
4>修改节点思路和原来一样
5>删除节点,由于双向链表可以自我删除节点,所以只需要找到待删除节点既可以删除节点
将前一个节点的next指向后一个节点,将后一个节点的pre指向前一个节点
temp.pre.next=temp.next;
这里当是最后一个节点的时候不能执行下面这句话,否则会造成问题,最后一个节点的下一个节点为空,若将空指向了前面,则会出现空指针的使用,所以条语句前面要加一个if语句来判断其是否为空
if(temp.next!=null)
temp.next.pre=temp.pre;
1)由双向链表实现的增删改查
代码实现
//先新建一个头结点,不存放具体的数据
private HeroNode2 head=new HeroNode2(0,"","");
//得到头结点
public HeroNode2 getHead() {
return head;
}
//将及节点添加到后面
public void add(HeroNode2 heroNode) {
//由于head的值不能改变,需要一个变量来辅助进行遍历
HeroNode2 temp=head;
//找到最后一位的链表节点
while(true) {
//只有最后一个节点才会为null,这个时候就可以退出了,这里就是为了找到最后一个节点的位置
if(temp.next==null) {
break;
}
//若没有找到最后一个节点,就将值进行后移,这样程序会不断的前进
temp=temp.next;
}
//此时退出循环后为最后一个节点,然后我们就可以将这个元素添加到最后一个节点的next域,
//并更新节点本身的pre域,从而形成双向链表
temp.next=heroNode;
heroNode.pre=temp;
}
//根据no编号来修改节点的信息,但不能修改no编号
public void updata(HeroNode2 newheroNode) {
//判断是否为空
if(head.next==null) {
System.out.println("链表为空");
return;
}
//找到需要修改的节点,根据no编号,还是要先定义一个辅助变量
HeroNode2 temp=head.next;
//定义是否找到该值
boolean flag=false;
while (true) {
if (temp==null) {
//已经遍历完链表了
break;
}
if(temp.no==newheroNode.no)
{
//已经找到了可以进行
flag=true;
break;
}
temp=temp.next;
}
//先判断flag的值有没有不一样
//根据flag来进行改值
if(flag) {
temp.name=newheroNode.name;
temp.nickname=newheroNode.nickname;
}else {
System.out.printf("没有找到该%d席执行官\n",newheroNode.no);
}
}
//根据no编号来删除节点的信息,由于双向链表可以自我删除节点,所以只需要找到待删除节点既可以删除节点
public void delete(int no) {
//判断是否为空
if(head.next==null) {
System.out.println("链表为空");
return;
}
//找到需要修改的节点,根据no编号,还是要先定义一个辅助变量
HeroNode2 temp=head.next;
//定义是否找到该值
boolean flag=false;
while (true) {
if (temp==null) {
//已经遍历完链表了
break;
}
if(temp.no==no)
{
//已经找到了可以进行
flag=true;
break;
}
temp=temp.next;
}
//根据flag来进行改值
if(flag) {
//将前一个节点的next指向后一个节点,将后一个节点的pre指向前一个节点
temp.pre.next=temp.next;
//这里当是最后一个节点的时候不能执行下面这句话,否则会造成问题,最后一个节点的下一个节点为空,
//若将空指向了前面,则会出现空指针的使用,所以条语句前面要加一个if语句来判断其是否为空
if(temp.next!=null)
{temp.next.pre=temp.pre;}
System.out.printf("第%d席执行官已经删除完毕\n",temp.no+1);
}else {
System.out.printf("没有找到该%d席执行官\n",no);
}
}
//显示所有链表(遍历)
public void list() {
//首先应判断一下链表是否为空
if(head.next==null) {
System.out.println("链表的值为空,不能进行遍历");
return;
}
//跟add()同样的是,由于head的值不能改变,需要一个变量来辅助进行遍历
HeroNode2 temp=head.next;
while(true) {
//首先要有结束语句,否则程序会陷入死循环
//结束条件就是到最后一个节点
if(temp==null) {
break;
}
//若没有跳出程序,就会一直输出显示语句
System.out.println(temp);
//将值进行后移,这样程序会不断的前进
temp=temp.next;
}
}
}
//定义HeroNode,每个HeroNode对象就是一个节点
class HeroNode2{
public int no;
public String name;
public String nickname;
public HeroNode2 pre; //指向前一个节点,所以要定义一个HeroNode类型的,默认为null
public HeroNode2 next; //指向下一个节点,所以要定义一个HeroNode类型的,默认为null
public HeroNode2(int no, String name, String nickname) {
this.no = no;
this.name = name;
this.nickname = nickname;
}
//为了显示放方便,改写toString
//在改写时不应该放next域,因为next域会一直输出下一个节点,而下个节点也有next域,会将所有节点输出在一行上,所有要将next域去掉
@Override
public String toString() {
return "HeroNode2 [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
}
}