数据结构之链表

本文对比了数组和链表的特点,指出链表在查询时的时间复杂度高但插入删除效率优于数组。介绍了链表的分类,如单向、循环、双向链表,并探讨了链表操作的时间复杂度。文章重点分享了六种编写链表代码的技巧,包括理解指针、防止指针丢失和内存泄漏、利用哨兵简化实现、处理边界条件、画图辅助思考以及多写多练,以帮助提升链表编程能力。
摘要由CSDN通过智能技术生成

数组和链表对比

数组是连续的内存区域、链表不是连续的内存区域。

因此,数组在通过下标查询时的时间复杂度低,而链表在查询时需要遍历链表,所以时间复杂度较高。

对于插入和删除,因为数组是连续的内存区域,所以每次插入和删除都需要做数据的迁移,因此时间复杂度较高。而链表因为在内存区域本身就不是连续的,所以时间复杂度比数组低。

链表分类

常见的有:单向链表、循环链表、双向链表、双向循环链表。

链表时间复杂度

查找:O(n)
插入、删除:O(1)
注:双向链表在很多情况下的查找、插入、删除时间复杂度都要低于单向链表,是一种用空间换时间的方式。

写链表代码技巧

技巧一:理解指针或引用的含义

实际上,如果画个图看懂链表的结构并不是很难。难点在于链表往往伴随着指针。和指针混在一起就容易难以理解。所以,要想写对链表代码,一定要理解清楚指针的用法。

技巧二:警惕指针丢失和内存泄漏

在这里插入图片描述
(图来自王争《数据结构与算法之美》课程)
如图,当我们希望在a结点与b结点之间插入结点x,那么,如果我们这么写:

p->next = x; // 将 p 的 next 指针指向 x 结点;
x->next = p->next; // 将 x 的结点的 next 指针指向 b 结点;

则会出现指针丢失的情况,因为b结点的地址存储于p->next中,而第一步我们就将p->next中存储的地址换为了x结点的地址,那么b结点的地址就丢失了。此时我们需要x->next指针存储b的地址却已经找不到b结点的地址了。

解决的办法就是把上面两个代码调换下位置。

当我们删除链表结点时,一定要记得手动释放内存空间,否则会出现内存泄漏的情况。当然,对于像Java这种有虚拟机自动管理内存的语言,就不需要考虑这些了。

技巧三:利用哨兵简化实现难度

简单的说,就是给单链表加一个哨兵结点,如图:
在这里插入图片描述
(图来自王争《数据结构与算法之美》课程)
这样我们在插入结点时,碰到插入头节点也无需进行额外判断。在删除结点时,碰到删除最后一个结点也无需进行额外判断。

技巧四:重点留意边界条件处理

在写代码时,当正常情况下程序运行时,最应当注意的是边界情况与异常情况,边界情况与异常情况可以处理的很好,这个程序代码才可以说是健壮的。

在写链表代码时,有如下几个边界条件需要重点留意:

  • 如果链表为空时,代码能否正常工作?
  • 如果链表只包含一个结点时,代码是否能正常工作?
  • 如果链表只包含两个结点时,代码是否能正常工作?
  • 代码逻辑在处理头结点和尾结点的时候,是否能正常工作?

技巧五:举例画图,辅助思考

在写链表代码时,如果脑袋里装了太多的处理过程总是会比较吃力的,此时可以借助画图的方式来帮助自己理清思路,辅助思考。

技巧六:多写多练

凡是不肯花相应的时间和精力是一定做不好的。所以要多花时间和精力做练习。

常见链表操作

  • 单链表反转
  • 链表中环的检测
  • 两个有序的链表合并
  • 删除链表倒数第n个结点
  • 求链表的中间结点

总结

写链表代码不是件简单的事,必须付出相应的时间和精力才会有所成长。然后同时也要注意使用以上技巧,会有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值