一.数组:
优点:
- 地址连续,访问任意一项都是常数级别O(1);
缺点:
- 删除,增加元素时间复杂度高,需要遍历,一般为O(n),插入前保证数组的size足够;
- 数组size较小,会进行扩容,拷贝等低效的操作。
二.链表: LRU cache
单链表,双向链表(),循环链表(头尾相连,尾指针指向头指针)
优点:
- 灵活,插入不需要扩容、移动其他元素或者拷贝等操作,O(1);
缺点:
- 占用内存,32系统一个指针4字节;
- 遍历、查找不方便,必须挨个遍历,不能用下表访问,一般为O(n)。
三.跳表: 是对于链表的优化,其中在Redis中应用广泛
链表的访问速度比较慢,寻找一个元素需要挨个遍历,优化:升维,空间换时间
优化思路与方案:
链表每次遍历的 粒度是一个元素,可不可能一次走两步、三步…
答案是肯定的.
方案:比如支持一次走两步的遍历方式
将当前元素A的next的next 的地址addr1记录下来,假设A的next的next元素是C,那么就将C的地址addr2也记录下来,以此类推。其中addr1和addr2以链表的形式组织起来,addr1的next指针指向addr2,而addr1保存的是A的地址。
假设A和C之间的元素是B,以前从A到C,需要走两步,现在只需要一步。
同理可得,L2级别的索引是不是也可以增加一层索引,这样是不是跳得更远?
- 一次走一步;
- 一次走两步;
- 一次走四步;
- 一次走八步
- …
查询时间复杂度:O(logn)
缺点:
- 维护成本高,增加删除都需要更新索引;
- 空间复杂度较高,O(n)