05数据结构之链表上

2019-10-19  本文已影响0人  ssas_

部分摘自专栏评论

1.关于缓存和缓存淘汰策略

  1. 什么是缓存?
    缓存是一种提高数据读取性能的技术,在硬件设计、软件开发中都有着非广泛的应用,比如常见的CPU缓存、数据库缓存、浏览器缓存等等。
  2. 什么是缓存淘汰策略
    指的是当缓存被用满时清理数据的优先顺序。
  3. 为什么使用缓存淘汰策略?
    缓存的大小是有限的,当缓存被用满时,哪些数据需要被清理出去,哪些数据应该被保留下来?需要用到缓存淘汰策略。
  4. 有哪些缓存淘汰策略
    常见的3种包括先进先出策略FIFO(First In,First Out)、最少使用策略LFU(Least Frenquently Used)、最近最少使用策略LRU(Least Recently Used)。
  5. 链表实现LRU缓存淘汰策略
    当访问的数据没有存储在缓存的链表中时,直接将数据插入链表表头,时间复杂度为O(1);当访问的数据存在于存储的链表中时,将该数据对应的节点,插入到链表表头,时间复杂度为O(n)。如果缓存被占满,则从链表尾部的数据开始清理,时间复杂度为O(1)
  6. 数组实现LRU缓存淘汰策略
    方式一:首位置保存最新访问数据,末尾位置优先清理
    当访问的数据未存在于缓存的数组中时,直接将数据插入数组第一个元素位置,此时数组所有元素需要向后移动1个位置,时间复杂度为O(n);当访问的数据存在于缓存的数组中时,查找到数据并将其插入数组的第一个位置,此时亦需移动数组元素,时间复杂度为O(n)。缓存用满时,则清理掉末尾的数据,时间复杂度为O(1)。
    方式二:首位置优先清理,末尾位置保存最新访问数据
    当访问的数据未存在于缓存的数组中时,直接将数据添加进数组作为当前最有一个元素时间复杂度为O(1);当访问的数据存在于缓存的数组中时,查找到数据并将其插入当前数组最后一个元素的位置,此时亦需移动数组元素,时间复杂度为O(n)。缓存用满时,则清理掉数组首位置的元素,且剩余数组元素需整体前移一位,时间复杂度为O(n)。(优化:清理的时候可以考虑一次性清理一定数量,从而降低清理次数,提高性能。)
  7. 如何通过单链表实现“判断某个字符串是否为水仙花字符串”?(比如 上海自来水来自海上)
    1)前提:字符串以单个字符的形式存储在单链表中。
    2)遍历链表,判断字符个数是否为奇数,若为偶数,则不是。
    3)将链表中的字符倒序存储一份在另一个链表中。
    4)同步遍历2个链表,比较对应的字符是否相等,若相等,则是水仙花字串,否则,不是。
  8. 设计思想
    时空替换思想:“用空间换时间” 与 “用时间换空间”
    当内存空间充足的时候,如果我们更加追求代码的执行速度,我们就可以选择空间复杂度相对较高,时间复杂度小相对较低的算法和数据结构,缓存就是空间换时间的例子。如果内存比较紧缺,比如代码跑在手机或者单片机上,这时,就要反过来用时间换空间的思路。

2.关于链表

  1. 什么是链表
  1. 链表的特点
  1. 插入、删除数据效率高O(1)级别(只需更改指针指向即可),随机访问效率低O(n)级别,因为链表中额数据并非连续存储的,无法向数组一样根据首地址和下标,通过寻址公式就能直接计算出对应的内存地址,需要从链头至链尾进行遍历
  2. 对链表来说,因为链表中的每个结点都需要消耗额外的存储空间去存储一份指向下一结点的指针,内存消耗会翻倍,对链表进行频繁的插入、删除操作,还会导致频繁的内存申请和释放,容易造成内存碎片,对某些语言,会导致频繁的GC
  1. 常用链表:单链表、循环链表和双向链表
4.链表和数组性能大比拼
  1. 插入、删除、随机访问操作的时间复杂度


    image.png
  2. 数组简单易用,在实现上使用的是连续的内存空间,可以借助CPU的缓存机制,预读数组中的数据,访问效率更高。链表不是连续存在于内存中的,对CPU缓存不友好,没有办法有效预读。
    CPU在从内存读取数据的时候,会先把读取到的数据加载到CPU的缓存中。而CPU每次从内存读取数据并不是只读取那个特定要访问的地址,而是读取一个数据块(这个大小我不太确定。。)并保存到CPU缓存中,然后下次访问内存数据的时候就会先从CPU缓存开始查找,如果找到就不需要再从内存中取。这样就实现了比内存访问速度更快的机制,也就是CPU缓存存在的意义:为了弥补内存访问速度过慢与CPU执行速度快之间的差异而引入。
  3. 大小固定,若存储空间不足,需进行扩容,一旦扩容就要进行数据拷贝制,而这是非常费时的
上一篇 下一篇

猜你喜欢

热点阅读