06 - 双向链表

Posted liujiaqi1101

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了06 - 双向链表相关的知识,希望对你有一定的参考价值。

1. 双向链表CRUD

1.1 思路分析

技术图片

  • 遍历
    • 遍历和单链表一样,但可以有2个方向:往前 和 往后
  • 添加(默认添加到链尾)
    • 通过遍历先找到当前双向链表的尾结点
    • temp.next = newNode;
    • newNode.pre = temp;
  • 修改
    • 原理与单链表相同
  • 删除
    • 因为是双向链表,故可直接找到 [待删除结点],实现自我删除
    • temp.pre.next = temp.next;
    • temp.next.pre = temp.pre;

1.2 代码实现

public class DoubleLinkedList {
    // 先初始化 [头结点], 头结点不存放数据
    private HeroNode2 head = new HeroNode2(0,"","");
    
    public HeroNode2 getHead() {
        return head;
    }

    // 添加结点到双向链表(追加)
    public void add(HeroNode2 node) {
        // 1. 找到 [尾结点]
        // 1.1 定义一个临时变量, 用来指向链表当前遍历到的元素
        HeroNode2 temp = head;
        // 1.2 遍历:当退出while循环时, temp此时指向的是尾结点
        while(temp.next != null)
            temp = temp.next;
        // 2. 追加(注意是双向链表)
        temp.next = node;
        node.pre = temp;
    }

    // 按编号顺序将结点到链表(如果有这个排名, 则添加失败, 并给出提示)
    public void insertByOrder(HeroNode2 node) {
        // 1. 找到 新结点 要插入的位置(遍历 + 辅助变量)
        HeroNode2 temp = head;
        // 用来标识新结点的编号是否已存在
        boolean flag = false;
        // 循环终止时, temp指向链表尾结点
        while(temp.next != null) { 
            // temp指向新结点要放置位置的前一个结点
            if(temp.next.no > node.no) { // find it! 
                break;
            } else if(temp.next.no == node.no) { // 说明编号已存在
                flag = true;
                break;
            }
            temp = temp.next; // 后移
        }

        if(!flag) { // 2. 新结点应插入到 temp 和 temp.next 之间
            node.next = temp.next;
            node.pre = temp;
            temp.next = node;
        } else { // 不能加入, 编号已存在
            System.out.printf("编号%d已存在, 不能插入
", node.no);
        }
    }
        
    
    // 根据编号修改结点数据
    public void updateByNo(HeroNode2 node) {
        // 判断链表是否空
        if(head.next == null) 
            System.out.println("链表为空");
        // 找到需要修改的结点
        HeroNode2 temp = head.next;
        // 是否找到该结点
        boolean flag = false; 
        while(temp.next != null) {
            if(temp.no == node.no) {
                flag = true;
                break;
            }
            temp = temp.next;
        }
        // 根据 flag 是否找到要修改的结点
        if(flag) {
            temp.name = node.name;
            temp.nickname = node.nickname;
        } else 
            System.out.printf("不存在编号为%d的结点
", node.no);
    }
    
    // 删除结点(自我删除)
    public void deleteNode(int no) {
        // 判断链表是否空
        if(head.next == null) {
            System.out.println("链表为空");
            return;
        }
        // 对于双向链表, 直接找到 待删除结点 即可
        HeroNode2 temp = head.next;
        boolean flag = false;
        while(temp != null) {
            if(temp.no == no) {
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if(flag) {
            // 待删除结点因没有任何引用指向, 故会被垃圾回收机制回收
            temp.pre.next = temp.next;
            // 如果删除的是尾结点就不需要执行下面这句(否则会报空指针异常)
            if(temp.next != null)
                temp.next.pre = temp.pre;
        } else 
            System.out.printf("不存在编号为%d的结点
", no);
    }

    // 打印链表(遍历)
    public void showList() {
        if(head.next == null) {
            System.out.println("链表为空");
            return;
        }
        
        // 头结点不能动, 故需要一个临时变量来遍历
        HeroNode2 temp = head.next;
        while(temp != null) {
            System.out.println(temp);
            temp = temp.next;
        }
    }
}

class HeroNode2 {
    public int no;
    public String name;
    public String nickname;
    public HeroNode2 next;
    public HeroNode2 pre;
    
    public HeroNode2(int no, String name, String nickname) {
        super();
        this.no = no;
        this.name = name;
        this.nickname = nickname;
    }

    @Override
    public String toString() {
        return "HeroNode2 [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
    }
}

以上是关于06 - 双向链表的主要内容,如果未能解决你的问题,请参考以下文章

2021-06-02:给定一棵搜索二叉树头节点,转化成首尾相接的有序双向链表。

需要一些关于 C++ 中的类的建议,双向链表

双向链表JAVA代码

Prolog中的双向链表

Java中双向链表的代码实现

双向链表是非线性数据结构还是线性数据结构?