【小白学算法】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种情况的结果都符合预期。
三、单链表结构与顺序存储结构的优缺点
- 查找
单链表时间复杂度为O(n),而顺序存储结构则是O(1),更有优势。 - 插入和删除
顺序结构平均需要移动表长的一半的元素,时间复杂度为0(n)。
而单链表在找到目标位置后,插入和删除操作的时间复杂度是O(1),效率更高。
没有完美的方案,都有自己的优势,所以具体还是要根据实际需求来定。
比如说,需求是高频查找,增删很少,顺序结构更适合。反之,单链表结构更合适。
--不要用肉体的勤奋,去掩盖思考的懒惰--