【数据结构】链式存储:链表(无头双向链表实现)

目录

🥇一:无头双向链表

🎒二、无头双向链表的实现

📘1.创建节点类

📒2.创建链表

📗3.打印链表

📕4.查找是否包含关键字key是否在单链表当中

📙5.得到单链表的长度

📒6.任意位置插入,第一个数据节点为0号下标

📘7.删除第一次出现关键字为key的节点

📗8.删除所有值为key的节点

📕9.清空链表


 

🥇一:无头双向链表

c9710492a62546e5a35fecc6ecd69441.png

🎒二、无头双向链表的实现

📘1.创建节点类

🌈节点由val域(数据域),prev(前驱),next(后继),对于prev域,其是引用类型,存放上一个节点的地址;对于next域,其是引用类型,存放下一个节点的地址。

    static class ListNote {
        public int val;
        public ListNote prev;//前驱
        public ListNote next;//后继

        public ListNote(int val) {
            this.val = val;
        }
        
    }
    public ListNote head;

📒2.创建链表

1️⃣头插法:头插法是指在链表的头节点的位置插入一个新节点,定义一个node表示该节点,然后就是对node的next进行赋值

 此时我们需要用到prev(前驱),如图所示:

双向链表和单向链表有一点不同的是:双向链表会有一个改良——会新增一个引用(last:永远指向最后一个节点),如果只有一个节点,那么head和last同时指向这个节点

新增的最后一个节点的好处就是:在进行尾插法的时候直接可以找到尾部进行插入

cda4c60723534ca1a154dfa6dbd5a0a7.png

    public ListNote last;//定义最后一个节点
    //头插法
    public void addFirst(int data){
        ListNote node = new ListNote(data);
        if(head == null) {
            head = node;
            last = node;
        }else {
            node.next = head;
            head.prev = node;
            node = head;
        }
    }

3️⃣尾插法:尾插法是指在链表的尾节点的位置插入一个新节点,定义一个node表示该节点,然后就是对原来最后一个节点的next进行赋值。

🔑如果只有一个节点,即node=head=last;如果多个节点在最后插入需要改两个数据,如图所示

fb5ec5cee2654d1b86e9570515a0df52.png

📗3.打印链表

➡️为了使head一直存在且有意义,我们在display()函数中定义一个cur:Node cur = head;来替代head。

    public void display(){
        ListNote cur = head;
        if(cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
        System.out.println();
    }

❓做在这里我们并没有使用到prev(前驱),即如果用不到就不需要使用了

📕4.查找是否包含关键字key是否在单链表当中

    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key){
        ListNote cur = head;
        while (cur != null) {
            if(cur.val == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

📙5.得到单链表的长度

    //得到单链表的长度
    public int size(){
        int len = 0;
        ListNote cur = head;
        if (cur != null) {
            len++;
            cur = cur.next;
        }
        return len;
    }

📒6.任意位置插入,第一个数据节点为0号下标

1️⃣首先,在头部插入一个节点——头插法;2️⃣在最后一个位置插入——尾插法

3️⃣在中间位置插入,需要改变4个位置,如图所示

ce71bb27f6254362988320db30590dde.png

    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data){
        if(index < 0 || index > size()) {
            throw new ListIndexOutOfExpection();
        }
        if(index == 0) {
            addFirst(data);
            return;
        }
        if(index == size()) {
            addLast(data);
            return;
        }
        ListNote cur = findIndex(index);
        ListNote node = new ListNote(data);
        node.next = cur;
        cur.prev.next = node;
        //注意顺序不能变
        node.prev = cur.prev;
        cur.prev = node;
    }

    private ListNote findIndex(int index) {
        ListNote cur = head;
        while (index != 0) {
            cur = cur.next;
            index--;
        }
        return cur;
    }

📘7.删除第一次出现关键字为key的节点

1️⃣首先,删除头节点:head = head.next;;2️⃣在删除中间和尾巴节点时,如图所示

58495db2a2404e969d4d93e05759fe8c.png

    //删除第一次出现关键字为key的节点
    public void remove(int key){
        ListNote cur = head;
        while (cur != null) {
            //开始删除
            if(cur.val == key) {
                //1.删除头节点
                if(cur == head) {
                    head = head.next;
                    //只有一个节点
                    if(head != null) {
                        head.prev = null;
                    }
                }else {
                    //中间  尾巴
                    cur.prev.next = cur.next;
                    //不是尾巴节点
                    if(cur.next != null) {
                        cur.next.prev = cur.prev;
                    }else {
                        //是尾巴节点
                        last = last.next;
                    }
                }
                return;
            }
            cur = cur.next;
        }
    }

📗8.删除所有值为key的节点

    //删除所有值为key的节点
    public void removeAllKey(int key){
        ListNote cur = head;
        while (cur != null) {
            //开始删除
            if(cur.val == key) {
                //1.删除头节点
                if(cur == head) {
                    head = head.next;
                    //只有一个节点
                    if(head != null) {
                        head.prev = null;
                    }
                }else {
                    //中间  尾巴
                    cur.prev.next = cur.next;
                    //不是尾巴节点
                    if(cur.next != null) {
                        cur.next.prev = cur.prev;
                    }else {
                        //是尾巴节点
                        last = last.next;
                    }
                }
            }
            cur = cur.next;
        }
    }

📕9.清空链表

🔑双向列表不可以把头和尾置为null;需要把每个节点都置为null

➡️定义一个cur:ListNode cur = head;在定义一个curNext,为了方便到找cur的下一个链表,并且置为null

0f57c5096d08404c8a5b8759322c97c1.png

    public void clear(){
        ListNote cur = head;
        while (cur != null) {
            ListNote curNext = cur.next;
            cur.prev = null;
            cur.next = null;
            cur = curNext;
        }
        head = null;
        last = null;
    }

 

 

 

 

 

 

  • 19
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奋斗小温

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值