单双向链表对比
- 数据结构异同
双向链表和单链表相比,其ListNode节点的数据结构当中多了一个变量是节点类型的pre变量,pre用来指向当前节点的前一个节点。 - 查找方向
单链表只能向后查找,双向链表可以向后向前查找。 - 操作思路的异同
- 遍历:思路基本相同,但双向链表可以向前,也可以向后;
- 添加:默认添加到双向链表的最后;先找到最后一个节点,同时修改最后一个节点的next域和新节点的pre域。
- 修改:思路相同
- 删除:因为是双向链表,可以向前追踪上一个节点,因此可以实现节点的自我删除;直接找到要删除的节点,分别修改其前一个节点的next域,和后一个节点的pre域。
注意,如果待删除节点是最后一个节点,要考虑其next域为空的问题。 - 根据排名添加:这个同样要注意节点next域为空的问题。
双向链表代码实现
package ds.sq.linkedlist;
public class DoubleLinkedListDemo {
public static void main(String[] args){
dHeroNode hero1=new dHeroNode(1,"宋江","及时雨");
dHeroNode hero2=new dHeroNode(2,"卢俊义","玉麒麟");
dHeroNode hero3=new dHeroNode(3,"吴用","智多星");
dHeroNode hero4=new dHeroNode(4,"林冲","豹子头");
DoubleLinkedList doubleLinkedList=new DoubleLinkedList();
//【显示list】
System.out.println("【测试1】初始化链表为空时:");
doubleLinkedList.list();
//1.测试:【根据排名添加addByOrder】添加顺序1、3、2、4
doubleLinkedList.addByOrder(hero1);
doubleLinkedList.addByOrder(hero3);
doubleLinkedList.addByOrder(hero2);
doubleLinkedList.addByOrder(hero4);
System.out.println("【测试2】根据排名添加:");
doubleLinkedList.list();
//2.测试:【修改】
System.out.println("【测试3】修改:");
dHeroNode mHero1=new dHeroNode(1,"Song Jiang","Ji Shiyu");
doubleLinkedList.modify(mHero1);
doubleLinkedList.list();
//3.测试:【删除】
System.out.println("【测试4】删除:");
doubleLinkedList.del(5);
doubleLinkedList.list();
}
}
class dHeroNode{
public int no;
public String name;
public String nickname;
public dHeroNode next;
public dHeroNode pre;
public dHeroNode(int hno,String hname,String hnickname){
this.no=hno;
=hname;
this.nickname=hnickname;
}
public String toString(){
return "dHeroNode [no"+no+"]name["+name+"]nickname["+nickname+"]";
}
}
class DoubleLinkedList{
private dHeroNode head=new dHeroNode(0,"","");
public void add(dHeroNode dheroNode){
//因为head节点不能动 因此我们需要一个辅助变量
dHeroNode tHeroNode=head;
while(true){
if(tHeroNode.next==null){
tHeroNode.next=dheroNode;
dheroNode.pre=tHeroNode;
break;
}
// 如果没有找到就将t后移
tHeroNode=tHeroNode.next;
}
}
//考虑编号的顺序时
public void addByOrder(dHeroNode dheroNode){
//因为头结点不能动,我们仍然通过一个辅助指针,帮助找到添加的位置
//找的temp位于添加位置的前一个结点,否则加入不了
dHeroNode tHeroNode=head;
boolean flag=false;
while(true){
if(tHeroNode.next==null){//说明链表已经到最后
break;
}
if( tHeroNode.next.no>dheroNode.no){
break;
}else if(tHeroNode.next.no==dheroNode.no){
flag=true;
break;
}
tHeroNode=tHeroNode.next;//后移
}
if(flag==true){
//不可以添加
System.out.printf("准备插入的英雄的编号 %d 已经存在\n",dheroNode.no);
}else{
dheroNode.next=tHeroNode.next;
if(tHeroNode.next!=null){tHeroNode.next.pre=dheroNode;}
tHeroNode.next=dheroNode;
dheroNode.pre=tHeroNode;
}
}
public void list(){
if(head.next==null){
System.out.println("链表为空");
return;
}
dHeroNode tHeroNode=head.next; //这里直接指向第一个有编号的节点,避免程序输出头结点;
while(true){
//是否到链表最后
if(tHeroNode==null){
break;
}
//输出节点信息
System.out.println(tHeroNode);
tHeroNode=tHeroNode.next;
}
}
public void modify(dHeroNode dheroNode){
dHeroNode tHeroNode=head;
boolean flag=false;
while(true) {
if (head.next==null||tHeroNode==null) {
break;
}
if(tHeroNode.no==dheroNode.no){
flag=true;
break;
}else{
tHeroNode=tHeroNode.next;
}
}
if(flag){
tHeroNode.nickname=dheroNode.nickname;
tHeroNode.name=dheroNode.name;
}
else{
System.out.println("未找到相关人物,无法修改。");
}
}
public void del(int no){
dHeroNode tHeroNode=head;
boolean flag=false;
while(true){
if(head.next==null){
break;
}if(tHeroNode==null){
break;
}if(tHeroNode.no==no){
flag=true;
break;
}
tHeroNode=tHeroNode.next;
}
if(flag){
tHeroNode.pre.next=tHeroNode.next;
if(tHeroNode.next!=null)tHeroNode.next.pre=tHeroNode.pre;
}
else{
System.out.printf("未找到no=[%d]的节点\n",no);
}
}
}
- 删除5号不存在的英雄时
- 删除1号英雄时: