1,链表结构
相比与数组,链表是稍微复杂一点的数据结构,这两个数据结构经常会放到一起来对比,所以我们先来看下这两者有什么区别。
先从底层存储结构看看:
数组:数组需要一块连续的空间来存储,对内存的要求比较高。如果我们申请一个50mb大小的内存,当内存中没有足够大的连续内存空间时,即使可用内存大于50mb,仍然会申请失败。
链表,结构如下:
链表不需要申请一块连续的内存,它通过指针将一组零散的内存串联起来使用,所以当可用内存大于50mb时,我们申请50mb大小的链表,根本就不会有问题。
链表常见结构:单链表、双向链表和循环链表。我们首先来看最简单、最常用的单链表。
2,单链表
如上面图示,就是一个单链表数据结构。其中有两个节点比较特殊,它们分别是头节点和尾节点。其中头节点用来记录链表的基地址,有了头节点,我们就可以遍历整个链表。而尾节点特殊的是:指针不是指向下一个节点,而是指向一个NULL,表示这是链表最后一个元素。
链表的插入和删除:
针对链表的插入和删除操作,我们只需要考虑相邻结点的指针改变,所以对应的时间复杂度是O(1)。
链表的访问:
但是,有利就有弊。链表要想随机访问第k个元素,就没有数组那么高效了。因为链表中的数据并非连续存储的,所以无法像数组那样,根据首地址和下标,通过寻址公式就能直接计算出对应的内存地址,而是需要根据指针一个结点一个结点地依次遍历,直到找到相应的结点。
3,循环链表
循环链表是一种特殊的单链表。它跟单链表唯一的区别就在尾结点。我们知道,单链表的尾结点指针指向空地址,表示这就是最后 的结点了。而循环链表的尾结点指针是指向链表的头结点。它像一个环一样首尾相连,所以叫作“循环”链表。
实际应用:和单链表相比,循环链表的优点是从链尾到链头比较方便。当要处理的数据具有环型结构特点时,就特别适合采用循环链表。比如著名的约瑟夫问题;
4,双向链表
链表需要额外的两个空间来存储后继结点和前驱结点的地址。所以,如果存储同样多的数据,双向链表要比单链表占用更多的内存空间。虽然两个指针比较浪费存储空间,但可以支持双向遍历,这样也带来了双向链表操作的灵活性。