java实现双向链表

参考于视频 尚硅谷Java数据结构与java算法,韩顺平数据结构与算法

单链表的缺点:

关于单链表的java实现可以查看我的上一篇文章(建议配合着学习):java实现单链表

  1. 单向链表,查找的方向只能是一个方向,而双向链表可以向前或者向后查找。
  2. 单向链表不能自我删除,需要靠辅助节点,而双向链表,则可以自我删除,所以在单链表删除时节点,总是找到temp,temp是待删除节点的前一个节点。

双向链表的操作分析与实现:

在这里插入图片描述

  1. 遍历方法和单链表一样,只是可以向前,也可以向后查找
  2. 添加(默认添加到双向链表的最后)
    (1)先找到双向链表的最后这个节点
    (2) temp.next = newNode
    (3) newNode.pre = temp;
  3. 修改思路和原来的单向链表一样
  4. 删除
    (1)因为是双向链表,因此,我们可以实现自我删除某个节点
    (2)直接找到要删除的这个节点,比如temp
    (3) temp.pre.next = temp.next (理解)
    (4) temp.next.pre = temp.pre;

实现思路与代码:

1.首先创建节点类

//每个DNode对象就是一个双向链表的节点
class DNode{
    public int no;
    public String name;  //data段包含no和name
    public DNode next;  //指向下一个节点
    public DNode pre;//指向前一个节点

    //构造器
    public DNode(int no, String name)
    {
        this.no = no;
        this.name = name;
    }

    //为了显示方法,重写toString
    @Override
    public String toString()
    {
        return "DNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}

2.创建一个双向链表的类,先初始化一个头节点,然后再编写方法

//创建一个双向链表的类
class DoubleLinkedList{
    //先初始化一个头节点,头节点不要动,不存放具体的数据
    private DNode head=new DNode(0,"");
    }

3.添加节点方法

public void add(DNode dNode){
        //因为head头不能动,因此我们需要一个辅助遍历temp(类似于指针)
        DNode temp=head;
        //遍历链表,找到最后
        while (true){
            //
            if(temp.next==null){
                break;
            }
            //如果没有找到最后,继续查找
            temp=temp.next;
        }
        //当退出while循环时,temp就指向了链表的最后
        //将最后这个节点的next,指向新的节点
        temp.next=dNode;
        dNode.pre=temp;
    }

4.修改节点data方法
(这里我们直接传入一个newNode,通过no找到节点,然后替换data)

public void update(DNode newNode){
        //判断是否为空
        if(head.next==null){
            System.out.println("链表为空~");
            return;
        }
        //找到需要修改的节点,根据no编号
        //先定义一个辅助temp遍历,temp需要找到更改节点的前一个节点
        DNode temp=head.next;
        boolean flag=false;//表示是否找到该节点
        while(true){
            if(temp==null){
                break; //已经遍历完链表
            }
            if(temp.no==newNode.no){
                //找到
                flag=true;
                break;
            }
            temp=temp.next;
        }
        //根据flag 判断是否找打要修改的节点
        if(flag){
            temp.name=newNode.name;
        }else {
            System.out.printf("没有找到 编号 %d 的节点,不能修改\n",newNode.no);
        }
    }

5.删除节点

//删除节点
    //思路:
    //1.对于双向链表,我们可以直接找到要删除的这个节点
    //2.找到后,自我删除即可 复杂,需要理解
    //因为是双向节点,temp可以指向需要删除的那个节点
    public void del(int no){
        //判断当前链表是否为空
        if (head.next == null)
        {
            System.out.println("链表为空,无需删除");
            return;
        }
        DNode temp=head;
        boolean flag=false; //标志是否找到待删除节点
        while(true){
            if(temp==null){ //已经到链表末尾
                break;
            }
            if(temp.no==no){
                //找到的待删除节点
                flag=true;
                break;
            }
            temp=temp.next; //temp后移,遍历
        }
        if(flag){//找到,可以删除
            temp.pre.next=temp.next;    //删除的节点会因为垃圾回收机制被回收
            if (temp.next != null) //将删除节点的下一个节点的pre指向 删除节点的pre,if判断是否删除的节点是最后一个(最后一个节点可以省去该步骤)
            {
                temp.next.pre=temp.pre;
            }
        }else {
            System.out.printf("要删除的%d 节点不存在\n",no);
        }
    }

6.遍历功能

//显示链表,通过辅助变量temp 遍历
    public void list(){
        //判断链表是否为空
        if (head.next == null)
        {
            System.out.printf("链表为空");
            return;
        }
        //因为头节点,不能动,因此我们需要一个辅助变量来变量
        DNode temp=head.next;
        while (true){
            //判断是否到链表最后
            if(temp==null){
                break;
            }
            //不为空,输出节点信息
            System.out.println(temp);
            //将temp后移
            temp=temp.next;
        }
    }

7.组合代码,编写主函数进行测试

public class DoubleLinkedListDemo
{
    public static void main(String[] args)
    {
        //测试
        System.out.println("双向链表的测试");
        //先创建节点
        DNode dnode1 = new DNode(1, "北京");
        DNode dnode2 = new DNode(2, "上海");
        DNode dnode3 = new DNode(3,"广州");
        DNode dnode4 = new DNode(4, "深圳");

        //创建一个双向链表
        DoubleLinkedList doubleLinkedList=new DoubleLinkedList();
        doubleLinkedList.add(dnode1);
        doubleLinkedList.add(dnode2);
        doubleLinkedList.add(dnode3);
        doubleLinkedList.add(dnode4);

        doubleLinkedList.list();

        //修改
        DNode newNode=new DNode(4,"重庆");
        doubleLinkedList.update(newNode);
        System.out.println("修改后的链表情况");
        doubleLinkedList.list();

        //删除
        doubleLinkedList.del(3);
        System.out.println("删除后的链表情况");
        doubleLinkedList.list();
    }

}

结果如下
在这里插入图片描述

完整代码实现:

最后以内部类的方式组合该代码:
DoubleLinkedListDemo.java:

/*
* 双向链表
* */
public class DoubleLinkedListDemo
{
    public static void main(String[] args)
    {
        //测试
        System.out.println("双向链表的测试");
        //先创建节点
        DNode dnode1 = new DNode(1, "北京");
        DNode dnode2 = new DNode(2, "上海");
        DNode dnode3 = new DNode(3,"广州");
        DNode dnode4 = new DNode(4, "深圳");

        //创建一个双向链表
        DoubleLinkedList doubleLinkedList=new DoubleLinkedList();
        doubleLinkedList.add(dnode1);
        doubleLinkedList.add(dnode2);
        doubleLinkedList.add(dnode3);
        doubleLinkedList.add(dnode4);

        doubleLinkedList.list();

        //修改
        DNode newNode=new DNode(4,"重庆");
        doubleLinkedList.update(newNode);
        System.out.println("修改后的链表情况");
        doubleLinkedList.list();

        //删除
        doubleLinkedList.del(3);
        System.out.println("删除后的链表情况");
        doubleLinkedList.list();
    }

}

//创建一个双向链表的类
class DoubleLinkedList{
    //先初始化一个头节点,头节点不要动,不存放具体的数据
    private DNode head=new DNode(0,"");

    //返回头节点
    //public DNode getHead(){
    //   return head;
    // }

    //显示链表,通过辅助变量temp 遍历
    public void list(){
        //判断链表是否为空
        if (head.next == null)
        {
            System.out.printf("链表为空");
            return;
        }
        //因为头节点,不能动,因此我们需要一个辅助变量来变量
        DNode temp=head.next;
        while (true){
            //判断是否到链表最后
            if(temp==null){
                break;
            }
            //不为空,输出节点信息
            System.out.println(temp);
            //将temp后移
            temp=temp.next;
        }
    }

    public void add(DNode dNode){
        //因为head头不能动,因此我们需要一个辅助遍历temp(类似于指针)
        DNode temp=head;
        //遍历链表,找到最后
        while (true){
            //
            if(temp.next==null){
                break;
            }
            //如果没有找到最后,继续查找
            temp=temp.next;
        }
        //当退出while循环时,temp就指向了链表的最后
        //将最后这个节点的next,指向新的节点
        temp.next=dNode;
        dNode.pre=temp;
    }

    public void update(DNode newNode){
        //判断是否为空
        if(head.next==null){
            System.out.println("链表为空~");
            return;
        }
        //找到需要修改的节点,根据no编号
        //先定义一个辅助temp遍历,temp需要找到更改节点的前一个节点
        DNode temp=head.next;
        boolean flag=false;//表示是否找到该节点
        while(true){
            if(temp==null){
                break; //已经遍历完链表
            }
            if(temp.no==newNode.no){
                //找到
                flag=true;
                break;
            }
            temp=temp.next;
        }
        //根据flag 判断是否找打要修改的节点
        if(flag){
            temp.name=newNode.name;
        }else {
            System.out.printf("没有找到 编号 %d 的节点,不能修改\n",newNode.no);
        }
    }

    //删除节点
    //思路:
    //1.对于双向链表,我们可以直接找到要删除的这个节点
    //2.找到后,自我删除即可 复杂,需要理解
    //因为是双向节点,temp可以指向需要删除的那个节点
    public void del(int no){
        //判断当前链表是否为空
        if (head.next == null)
        {
            System.out.println("链表为空,无需删除");
            return;
        }
        DNode temp=head;
        boolean flag=false; //标志是否找到待删除节点
        while(true){
            if(temp==null){ //已经到链表末尾
                break;
            }
            if(temp.no==no){
                //找到的待删除节点
                flag=true;
                break;
            }
            temp=temp.next; //temp后移,遍历
        }
        if(flag){//找到,可以删除
            temp.pre.next=temp.next;    //删除的节点会因为垃圾回收机制被回收
            if (temp.next != null) //将删除节点的下一个节点的pre指向 删除节点的pre,if判断是否删除的节点是最后一个(最后一个节点可以省去该步骤)
            {
                temp.next.pre=temp.pre;
            }
        }else {
            System.out.printf("要删除的%d 节点不存在\n",no);
        }
    }
}

//每个DNode对象就是一个双向链表的节点
class DNode{
    public int no;
    public String name;  //data
    public DNode next;  //指向下一个节点
    public DNode pre;//指向前一个节点

    //构造器
    public DNode(int no, String name)
    {
        this.no = no;
        this.name = name;
    }

    //为了显示方法,重写toString
    @Override
    public String toString()
    {
        return "DNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值