单链表的一些缺点:
1)
单向链表,
查找的方向只能是一个方向
,而双向链
表可以向前或者向后查找。
2)
单向链表不能自我删除,需要靠辅助节点 ,而双向
链表,则可以
自我删除
,所以前面我们单链表删除节点
时总是找到
temp,temp
是待删除节点的前一
个节点
分析双向链表的遍历,添加,修改,删除的操作思路:
1) 遍历 和 单链表一样,只是可以向前,也可以向后查找。节点需要增加一个pre属性
2) 添加 (默认添加到双向链表的最后)
(1) 先找到双向链表的最后这个节点
(2) temp.next = new Node
(3) new Node.pre = temp;
3) 修改 和原来的单向链表一样.
4) 删除
(1) 因为是双向链表,因此,我们可以实现自我删除某个节点
(2) 直接找到要删除的这个节点,比如temp
(3) temp.pre.next = temp.next
(4) temp.next.pre = temp.pre;
同样以英雄排行为例,
一、英雄节点类的定义
class HeroNode2{
public int No;
public String nickname;
public String name;
public HeroNode2 next;//指向下一个节点
public HeroNode2 pre;//指向上一个节点
public HeroNode2(int no, String nickname, String name) {
No = no;
this.nickname = nickname;
this.name = name;
}
@Override
public String toString() {
return "HeroNode2{" +
"No=" + No +
", nickname='" + nickname + '\'' +
", name='" + name + '\'' +
", ";
}
}
二、英雄双向链表类定义:
class DoubleLinkedList{
//初始化头加点,不存放具体数据
public final HeroNode2 head=new HeroNode2(0,"","");
... ...
1.添加节点 add
/** 添加节点
1.找到当前链表的最后一个节点
2.将最后节点的next指向新的节点,新节点的pre指向前一个节点*/
public void add(HeroNode2 heroNode2){
//需要辅助变量temp来遍历链表
HeroNode2 temp=head;
while (true){
if(temp.next==null){
temp.next=heroNode2;
heroNode2.pre=temp;
heroNode2.next=null;
break;
}
temp=temp.next;
}
}
@Test
public void testAdd(){
DoubleLinkedList linkedList=new DoubleLinkedList();
linkedList.add(new HeroNode2(1,"wz","wangzhuang"));
linkedList.add(new HeroNode2(2,"zp","zhouping"));
linkedList.showList();
}
结果:
HeroNode2{No=1, nickname='wz', name='wangzhuang',
HeroNode2{No=2, nickname='zp', name='zhouping',
2.修改节点 update
/** 根据No修改节点*/
public void update(HeroNode2 node){
HeroNode2 temp=head.next;
boolean flag=false;
//通过辅助变量temp遍历到待修改节点
while(true){
if(temp==null)break;
if(temp.No == node.No){
flag=true;
break;
}
temp=temp.next;
}
if(flag) {
temp.name = node.name;
temp.nickname = node.nickname;
}else System.out.println("编号 "+node.No+" 的结点未找到,修改失败!");
}
@Test
public void testUpdate(){
DoubleLinkedList linkedList=new DoubleLinkedList();
linkedList.add(new HeroNode2(1,"wz","wangzhuang"));
linkedList.add(new HeroNode2(2,"zp","zhouping"));
linkedList.update(new HeroNode2(1,"wzz","wangzhuangzhuang"));
linkedList.showList();
}
测试:
HeroNode2{No=1, nickname='wzz', name='wangzhuangzhuang',
HeroNode2{No=2, nickname='zp', name='zhouping',
3.删除节点 delete
/** 根据No删除节点。要用temp遍历到待删除结点*/
public void delete(int no){
HeroNode2 temp=head.next;
boolean flag=false;
while(true){
if(temp.No==no){
flag=true;
break;
}
if(temp.next==null)break;
temp=temp.next;
}
if(flag){
temp.pre.next=temp.next;
//若删除的是最后一个节点,可能会报空指针异常
if(temp.next != null) temp.next.pre=temp.pre;
}else System.out.println("编号 "+no+" 的结点未找到,删除失败!");
}
@Test
public void testDelete(){
DoubleLinkedList linkedList=new DoubleLinkedList();
linkedList.add(new HeroNode2(1,"wz","wangzhuang"));
linkedList.add(new HeroNode2(2,"zp","zhouping"));
linkedList.delete(2);
linkedList.showList();
}
测试:
HeroNode2{No=1, nickname='wz', name='wangzhuang',
4.判断是否空
/** 判断链表是否为空*/
public boolean isEmpty(){
return (head.next==null);
}
5.遍历链表
/** 遍历链表*/
public void showList(){
if(isEmpty()){
System.out.println("链表为空!");
return;
}
HeroNode2 temp=head.next;
while(true){
System.out.println(temp);
if(temp.next==null) break;
temp=temp.next;
}
}