Java双向链表操作分析和实现

  • 管理单向链表的缺点分析:

    1. 单向链表: 查找的方向只能是一个方向, 而双向链表可以向前或者向后查找
    2. 单向链表不能自我删除, 需要靠辅助节点, 而双向链表则可以自我删除,所以前面我们单链表删除时节点,总是找到temp的下一个节点来删除时节点, 总是找到temp temp是待删除节点的前一个节点(认真体会).
  • 分析双向链表的遍历, 添加, 修改, 删除的操作思路==>代码实现
    1. 遍历 方法和单链表一样, 只是可以向前, 也可以向后查找
    2. 添加 (默认添加到双向链表的最后)
      1. 先找到双向链表的最后这个节点
      2. temp.next = newHeroNode
      3. newHeroNode.pre = temp;
    3. 修改 思路和原来的单向链表一样
    4. 删除
      1. 因为是双向链表, 因此, 我们可以实现自我删除某个节点
      2. 直接找到要删除的这个节点,比如temp
      3. temp.pre.next = temp.next
      4. temp.next.pre = temp.pre
  • 使用带head头的双向链表实现

    package DataStructures;
    
    public class DoubleLinkedListDemo {
        public static void main(String[] args) {
            System.out.println("双向链表的测试");
            // 先创建节点
            HeroNode2 hero1 = new HeroNode2(1, "宋宋", "江江");
            HeroNode2 hero2 = new HeroNode2(2, "文文", "雨雨");
            HeroNode2 hero3 = new HeroNode2(3, "哈哈", "嘿嘿");
            HeroNode2 hero4 = new HeroNode2(4, "依依", "落落");
    
            // 创建双向链表
            DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
            doubleLinkedList.add(hero1);
            doubleLinkedList.add(hero2);
            doubleLinkedList.add(hero3);
            doubleLinkedList.add(hero4);
            doubleLinkedList.list();
    
            // 修改
            HeroNode2 newHeroNode = new HeroNode2(4,"胜胜","零零");
            doubleLinkedList.update(newHeroNode);
            System.out.println("修改后的链表情况");
            doubleLinkedList.list();
    
            // 删除
            doubleLinkedList.del(3);
            System.out.println("删除后的链表情况");
            doubleLinkedList.list();
            
        }
    }
    //创建一个双向链表的类
    class DoubleLinkedList {
        //先初始化一个头节点, 头节点不要动,
        private HeroNode2 head = new HeroNode2(0,"","");
    
        // 返回头节点
        public HeroNode2 getHead() {
            return head;
    
        }
    
        // 遍历双向链表的一个方法
    
        public void list() {
            // 判断链表是否为空
            if (head.next == null) {
                System.out.println("链表为空");
                return;
            }
            // 因为头节点, 不能动 因此我们需要一个辅助变量来遍历
            HeroNode2 temp = head.next;
            while(true) {
                // 判断是否到链表最后
                if (temp == null) {
                    break;
                }
                // 输出节点信息
                System.out.println(temp);
                // 将temp后移, 一定小心
                temp = temp.next;
            }
        }
    //添加一个节点到双向链表的最后
        public void add(HeroNode2 heroNode) {
            //因为head节点不能动, 因此我们需要一个辅助变量temp
            HeroNode2 temp = head;
            // 遍历链表, 找到最后
            while(true) {
                // 找到链表的最后
                if (temp.next == null) {
                    break;
                }
    //            如果没有找到最后,就将temp后移
                temp = temp.next;
            }
            // 当退出while循环时, temp就指向了链表的最后
            // 形成一个双向链表
            temp.next = heroNode;
            heroNode.pre = temp;
        }
    //修改一个节点的内容, 可以看到双向链表的节点内容修改和单向链表一样,只是节点的类型改成HeroNode2
        // 修改节点的信息, 根据no的编号来修改, 即no编号不能改
        //说明
        // 1. 根据newHeroNode 的no来修改即可
        public void update(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 判断是否找到要修改的节点
            if (flag) {
                temp.name = newHeroNode.name;
                temp.nickname = newHeroNode.nickname;
            } else { // 没有找到
                System.out.println("没有找到编号为%d 的节点, 不能修改\n" + newHeroNode.no);
            }
        }
    
        //从双向链表删除一个节点
        // 说明:
        // 对于双向链表, 我们可以直接找到要删除的这个节点
        // 找到后, 自我删除即可
        public void del(int no) {
            // 判断当前链表是否为空
            if (head.next == null) {
                System.out.println("链表为空,无法删除");
                return;
            }
    
            HeroNode2 temp = head.next; // 辅助变量(指针)
            boolean flag = false; // 标志是否找到待删除节点的
            while (true) {
                if (temp.next == null) { //已经到链表的最后
                    break;
                }
                if (temp.no == no) {
                    // 找到了待删除的前一个节点temp
                    flag = true;
                    break;
                }
                temp = temp.next;// temp后移 遍历
            }
            //判断flag
            if (flag) { // 找到
                // 可以删除
    //            temp.next = temp.next.next; // 单向链表
                temp.pre.next = temp.next;
    
                // 这里代码有问题, 如果是最后一个节点, 就不需要执行下面的代码, 否则会出现空指针
    //            temp.next.pre = temp.next;
                if (temp.next != null) {
                    temp.next.pre = temp.pre;
                }
            }else {
                System.out.println("要删除的%d 节点不存在\n" + no);
            }
        }
    
    }
    
    // 定义HeroNode2 , 每个HeroNode 对象就是一个节点
    class HeroNode2 {
        public int no;
        public String name;
        public String nickname;
        public HeroNode2 next; // 指向下一个节点 默认为null
        public HeroNode2 pre;// 指向前一个节点 默认为null
    
        // 构造器
        public HeroNode2(int no, String hName, String hNickname) {
            this.no = no;
            this.name = hName;
            this.nickname = hNickname;
        }
    
        // 为了显示方法, 我们重新toString
        @Override
        public String toString() {
            return "HeroNode{" +
                    "no=" + no +
                    ", name='" + name + '\'' +
                    ", nickname='" + nickname;
        }
    }
    

课后思考:

双向链表的第二种添加方式, 按照编号顺序,按照单链表的顺序添加,稍作修改即可
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值