四-中,Java实现双链表 0.8

四-中, 双链表( Double Linked List)

单链表结点中只有一个指向其后继的指针,这使得单链表只能从头结点依次顺序地向后遍历。若要访问某个结点的前驱结点(插入、删除操作时),只能从头开始遍历,访问后继结点的时间复杂度为O(1),访问前驱结点的时间复杂度为O(n)。

  • 为了克服单链表的上述缺点,引入了双链表,双链表结点中有两个指针pre(或prior)和next,分别指向其前驱结点和后继结点,如下图所示。

4.1 双链表的常用方法主要代码

双链表仅仅是在单链表的结点中增加了一个指向其前驱的pre指针,因此,在双链表中执行按值查找和按位查找的操作和单链表相同。但双链表在插入和删除操作的实现上,和单链表有着较大的不同。这是因为“链”变化时也需要对pre(或prior)指针做出修改,其关键在于保证在修改的过程中不断链。此外,双链表可以很方便地找到其前驱结点,因此,插入、删除结点算法的时间复杂度仅为O(1)。

双链表解决了访问前驱结点的问题;

4.1.2 双链表的普通插入,顺序插入, 定点插入(插入到指定结点后)和遍历输出

因为双链表有两个指针域,所以我们在一定要同时考虑两个指针域的引用的赋值!

  1. 双链表的普通插入:

按照结点添加顺序. 每需要添加一个结点,就要从头结点遍历到链表的尾部,然后把新的结点连接到尾部即可;

  • 主要实现代码:
   ///1. 双链表的普通插入(我们一定要照顾两条指针域!!!)
    public void add(Node node) {
        //临时变量temp
        Node temp = head;

        while (true) {
            if (temp.next == null)
                break;
            temp = temp.next;
        }
        //决定性语句
        temp.next = node;
        node.pre = temp;
    }
  1. 双链表的顺序插入和遍历输出

双链表的顺序插入是指链表按照某种规则顺序的组成链表,新结点的插入需要跟已经在链表中的结点一一比较,然后再插入到合适的位置上

这里跟单链表不同的是,我们需要特别注意,如果插入的位置在双链表的末尾,可能会出现空指针的情况,为了避免空指针,我们需要根据情况对可能会出现空指针的语句多加上一重判断!

顺序插入和打印链表的代码如下:


//结点类
    static class Node{
        Node next;
        Node pre;
        int num;
        ///构造器和toString方法
        public Node(int num){
            this.num = num;
        }
        public String toString(){
            return "num= "+num;
        }
    }
    /// 头结点
    Node head =new Node(0);

    ///结点的顺序插入
    /*
    结点顺序插入的三种情况:
    1. temp.next.num == node.num 如果不允许重复结点,则不插入链表中
    2. temp.next.num > node.num 找到了! 插入到temp的后面即可(注意有无next的区别噢)
    3. temp.next.num < node.num 还没找到, 继续找吧
     */

    public void addByOrder(Node node){
        //临时变量
        Node temp = head;
        boolean flag =false; //是否插入结点的标志
        while(true){
            if(temp.next == null){
                flag =true;
                break;
            }

            if(temp.next.num == node.num)
                break;
            if(temp.next.num > node.num){
                flag = true;
                break;
            }

                temp =temp.next;
        }

        if(flag){
            node.next = temp.next;
            node.pre = temp;
            temp.next = node;
            if(node.next != null)
                node.next.pre = node; 如果node在结点最后添加,node.next为空,所以我们需要加上一层判断
        }
    }
    ///4.双链表的打印
    public void list() {
        //临时变量
        Node temp = head;

        while (true) {
            if (temp.next == null)
                break;
            temp = temp.next;
            System.out.println(temp);
        }
    }
  1. 把结点插入到双链表的指定结点后, 具体实现可参考2中结点顺序插入到链表

4.1.3 双链表的查找,修改和删除

  1. 双链表的查找和修改

可以参考单链表的查找和修改, 代码几乎一致噢

  1. 双链表的删除:

如上图所示,我们需要删除链表中的2号结点, 在Java的具体实现事,我们需要让temp正好指向要删除的结点, 因为这样的话我们可以很方便的获取到删除结点的前驱结点!

  • 主要代码如下:
    ///掌管双链表结点删除的两句代码
    temp.pre.next = temp.next;
    temp.next.pre = temp.pre;

在删除双链表的结点时,我们要特别注意待删除结点的位置情况,如果要删除的结点正好处于双链表的最后一个, 那么在上面的删除代码第二句(②), temp.next是个null, null.pre就产生了空指针异常!

  • 所以我们如果在删除或者说插入遇到了这种类似的情况, 都需要对 第二句加上一个判断, if( temp.next != null)
public void del(Node node) {
        //临时变量
        Node temp = head;

        while (true) {
            if (temp.next == null) {
                System.out.println("未找到待删除的结点!");
                break;
            }
            temp = temp.next;
            ///删除操作:
            if (temp.num == node.num) {
                temp.pre.next = temp.next;

                if( temp.next != null) 在处理最后一个结点时,千万不要忘记这句话哦!
                    temp.next.pre = temp.pre;
                break;
            }

        }
    }

完整代码实例- Java实现双链表中的各种常用方法

posted @ 2022-05-26 20:31  青松城  阅读(38)  评论(0编辑  收藏  举报