【小白学算法】6.单链表的修改、删除

接着上一章继续来看单链表。
之前对单链表进行了遍历、插入的操作,本章继续用代码来实现修改以及删除。

一、单链表的修改

修改结点信息首先需要先找到对应的结点,接着上一章的代码,也就是英雄的排名no是不能修改的,要用来找结点。
其他的信息就可以动了。

另外,还要考虑到单链表中找不到对应要修改的结点的情况。这里代码就不全贴出来了,现在继续在SingleLinkedList
中增加修改结点信息的方法:

    // 修改结点信息
    // 根据结点的no来修改即可
    public void  update(HeroNode newHeroNode) {
        // 判断链表是否为空
        if (headNode.next == null) {
            System.out.println("链表为空");
            return;
        }
        // 借助辅助变量temp
        HeroNode temp = headNode.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.printf("未找到编号%d的结点,不可修改\n", newHeroNode.no);
        }
    }

在main方法中修改测试代码,看看结果是否符合预期。

    public static void main(String[] args) {
        // 测试
        HeroNode hero1 = new HeroNode(1, "易大师","无极剑圣");
        HeroNode hero2 = new HeroNode(2, "李青","盲僧");
        HeroNode hero3 = new HeroNode(3, "艾希","寒冰射手");
        HeroNode hero4 = new HeroNode(4, "菲奥娜","无双剑姬");

        // 创建链表
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        // 加入对象结点
        singleLinkedList.addByNo(hero1);
        singleLinkedList.addByNo(hero4);
        singleLinkedList.addByNo(hero2);
        singleLinkedList.addByNo(hero3);
        // 显示链表内容
        singleLinkedList.linkList();

        // 测试修改
        HeroNode hero5 = new HeroNode(2, "李青","瞎子");
        singleLinkedList.update(hero5);
        System.out.println("修改后的链表:");
        singleLinkedList.linkList();
    }

运行结果:

HeroNode{no=1, name='易大师', nickname='无极剑圣'}
HeroNode{no=2, name='李青', nickname='盲僧'}
HeroNode{no=3, name='艾希', nickname='寒冰射手'}
HeroNode{no=4, name='菲奥娜', nickname='无双剑姬'}
修改后的链表:
HeroNode{no=1, name='易大师', nickname='无极剑圣'}
HeroNode{no=2, name='李青', nickname='瞎子'}
HeroNode{no=3, name='艾希', nickname='寒冰射手'}
HeroNode{no=4, name='菲奥娜', nickname='无双剑姬'}

Process finished with exit code 0

继续修改一个不存在的结点:HeroNode hero5 = new HeroNode(11, "李青","瞎子");
测试结果:

HeroNode{no=1, name='易大师', nickname='无极剑圣'}
HeroNode{no=2, name='李青', nickname='盲僧'}
HeroNode{no=3, name='艾希', nickname='寒冰射手'}
HeroNode{no=4, name='菲奥娜', nickname='无双剑姬'}
未找到编号11的结点,不可修改
修改后的链表:
HeroNode{no=1, name='易大师', nickname='无极剑圣'}
HeroNode{no=2, name='李青', nickname='盲僧'}
HeroNode{no=3, name='艾希', nickname='寒冰射手'}
HeroNode{no=4, name='菲奥娜', nickname='无双剑姬'}

Process finished with exit code 0

二、单链表的删除

1、删除结点

要删除结点,依然要先找到这个结点。

如图所示,我要删除结点4,借助temp来遍历,找到要删除的结点。但是,temp不能指在结点4,得指向结点4的前一个。
因为这是个单向链表,结点4里记录的是下一个结点的位置信息,所以在结点4这是删不掉的。应该指在结点1,这样就可以
修改结点1的next指针,绕过结点4,指向结点8。

而此时的结点4,由于没有其他引用指向它,于是被垃圾回收机制回收,到此就完成了结点4的删除了。
继续用代码来模拟,新增一个结点删除的方法:

    // 删除结点
    public void delete(int no) {
        HeroNode temp = headNode;
        boolean flag = false;  // 标记是否找到待删除的结点的前一个结点
        while (true) {
            if (temp.next == null) {
                break;
            }
            if (temp.next.no == no) {
                // 找到待删除结点的前一个结点
                flag = true;
                break;
            }
            temp = temp.next; // temp后移操作

        }
        if (flag) {
            temp.next = temp.next.next;
        } else {
            System.out.printf("要删除的结点%d 不存在\n", no);
        }
    }

测试删除,我把首尾的1和4删掉。

删除后的链表:
HeroNode{no=2, name='李青', nickname='瞎子'}
HeroNode{no=3, name='艾希', nickname='寒冰射手'}

Process finished with exit code 0

我把链表里的结点全删掉:

删除后的链表:
链表为空

Process finished with exit code 0

2种情况的结果都符合预期。

三、单链表结构与顺序存储结构的优缺点

  1. 查找
    单链表时间复杂度为O(n),而顺序存储结构则是O(1),更有优势。
  2. 插入和删除
    顺序结构平均需要移动表长的一半的元素,时间复杂度为0(n)。
    而单链表在找到目标位置后,插入和删除操作的时间复杂度是O(1),效率更高。

没有完美的方案,都有自己的优势,所以具体还是要根据实际需求来定。
比如说,需求是高频查找,增删很少,顺序结构更适合。反之,单链表结构更合适。

posted @ 2021-03-26 10:08  把苹果咬哭的测试笔记  阅读(631)  评论(0编辑  收藏  举报