算法与数据结构:链表

        链表是一种不连续的线性数据结构。常见的有单链表,循环链表,双链表。
        链表通过指针将一组零散的内存块串联在一起,我们把内存块称为链表的结点。结点除了存储数据外,还存有指向其他结点的指针。指向后一个结点的指针称为后继指针(next),指向前一个结点的指针称为前驱指针(pre)

单链表.jpg

        单链表的尾结点指向一个null地址,代表这是链表的最后一个结点。与数组一样,链表也支持数据的查找,删除,插入。因为数组是一组连续的内存空间,所以在数组上进行插入删除操作时,需要做大量的数据搬移,时间复杂度是O(n),但是也正因为这种特性,数组适合随机访问数据(addr=base_addr+i*data_type_size)。而在链表上进行插入删除操作时,只需要改变结点的指针即可,对应的时间复杂度是O(1)。
image.png

        循环列表是一种特殊的单链表,单链表的最后一个结点next指针为null,变成循环列表只需要把该指针重新指向头结点即可。
image.png

        循环列表的优点是从链尾到链头比较方便,当要处理的数据具有环形结构特点时,适合采用循环链表。
双向链表结点含有两个指针,next和pre,分别指向后一个结点和前一个结点。
image.png

        所以,如果存储同样的数据,双链表比单链表更费内存空间,但是它也具有更好的灵活性。单链表结构需要找到一个结点的前驱结点时,需要从头结点遍历,而双链表结点本身就存储了前驱结点的地址。
        这里说一种非常重要的设计思想空间换时间。当内存空间充足时,我们更追求代码的执行速度,此时可以采用空间复杂度相对较高但时间复杂度较低的数据结构或算法。比如著名的LRU缓存淘汰算法就是利用了空间换时间的设计思想。如果我们把数据存储在硬盘上会比较节省内存,但是每一次查找数据都需要访问硬盘,会比较慢。但如果我们通过缓存技术,先将数据缓存在内存中,虽然比较耗费内存空间,但是数据查询速度大大提高。
        引申,双向循环列表
image.png

       CPU从内存中读取数据的时候,会先把读取到的数据加载到CPU的缓存中。而CPU每次从内存中读取数据并不只是读取那个特定的地址,而是读取一个数据块并加载到CPU缓存中,当下次要访问数据的时候,会先从缓存中开始查找,如果找到了就不需要再从内存中读取,这样就实现了比内存访问速度更快的机制。而对于数组来说,存储空间是连续的,所以CPU会把要访问数据的周边数据一并加载到CPU缓存中,访问效率更高,而链表是不连续的存储空间,所以对CPU缓存不太友好。

你可能感兴趣的:(算法与数据结构:链表)