链表(上)

扫码关注公众号,获取更多内容

目录

一、底层存储结构

二、常见的链表

1、单链表

2、循环链表

3、双向链表

4、双向循环链表

三、链表与数组性能


 

一、底层存储结构

我们观察下图

数组需要一块连续的内存空间来存储,对内存的要求比较高。如果我们申请一个 100MB 大小的数组,当内存中没有连续的、足够大的存储空间时,即便内存的剩余总可用空间大于 100MB,仍然会申请失败。

而链表恰恰相反,它并不需要一块连续的内存空间,它通过“指针”将一组零散的内存块串联起来使用,所以如果我们申请的是 100MB 大小的链表,根本不会有问题。

我们把内存块称为链表的“结点”,为了将所有的结点串起来,每个链表的结点除了存储数据之外,还需要记录链上的下一个结点的地址,我们把这个记录下个结点地址的指针叫作后继指针 next。

 

二、常见的链表

1、单链表

观察上图我们可以发现,有两个结点是比较特殊的,分别是第一个结点(头结点)和最后一个结点(尾节点)。其中头节点是用来记录链表的基地址,有了它,就可以遍历得到整条链表。而尾结点的指针不是指向下一个节点,而是指向一个空地址NULL,表示这是链表上最后一个结点。

与数组一样,链表也支持数据的查找、插入和删除。

针对链表进行插入和删除操作时,我们只需要考虑相邻结点指针的改变,所以时间复杂度是O(1)。

但当链表要随机访问第K个元素,就需要根据指针一个结点一个结点地依次遍历,直到找到对应的结点,时间复杂度是O(n)。

 

2、循环链表

循环链表是一种特殊的单链表,单链表的尾结点指针指向NULL,而循环链表的尾结点指针是指向链表的头结点。

 

3、双向链表

双链表支持两个方向,每个结点都有一个后继指针next指向后面的结点,还有一个前驱指针prev指向前面的结点。

双向链表需要额外的两个空间来存储后继结点和前驱结点地址。所以存储同样多的数据,双向链表占用更多的空间。虽然两个指针比较浪费存储空间,但可以支持双向遍历,使双向链表的操作更灵活。

 

4、双向循环链表

将双向链表与循环链表结合,我们可以得到双向循环链表。

 

三、链表与数组性能

在实际的软件开发中,不能仅仅利用复杂度分析就决定使用哪个数据结构来存储数据。

数组简单易用,在实现上使用的是连续的内存空间,可以借助 CPU 的缓存机制,预读数组中的数据,所以访问效率更高。而链表在内存中并不是连续存储,所以对 CPU 缓存不友好,没办法有效预读。

数组的缺点是大小固定,一经声明就要占用整块连续内存空间。如果声明的数组过大,系统可能没有足够的连续内存空间分配给它,导致“内存不足(out of memory)”。如果声明的数组过小,则可能出现不够用的情况。这时只能再申请一个更大的内存空间,把原数组拷贝进去,非常费时。链表本身没有大小的限制,天然地支持动态扩容,这也是它与数组最大的区别。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值