数据结构与算法-学习笔记(15)

217 阅读2分钟

为什么散列表和链表经常会一起使用?

数组占据随机访问的优势,却有需要连续内存的缺点。

链表具有可不连续存储的优势,但访问查找是线性的。

散列表和链表、跳表的混合使用,是为了结合数组和链表的优势,规避它们的不足。

我们可以得出数据结构和算法的重要性排行榜:连续空间 > 时间 > 碎片空间。

因此散列表和链表会一起来使用。

举例

LRU缓存淘汰算法

之前用链表实现,它的时间复杂度是O(n)。 利用散列表和链表可以优化到O(1)。

  1. 首先根据缓存数据的插入顺序进行排序,形成一个双向链表。
  2. 根据缓存数据data创建一个散列表,冲突的解决方式采用链表的形式。

hnext指针是为了连接散列表中的冲突链表; prev和next指针是双向链表的前继和后继指针。

这样在查询、插入、删除操作的时间复杂度都是O(1)。

Redis有序集合

对学生(id、name、score)对象数据集合进行一下操作:

  • 添加一个学生对象;
  • 按照id来删除学生对象;
  • 按照id来查找学生对象;
  • 按照score区间查找数据,如score在[100,356]之间的学生对象;
  • 按照score从小到大排序学生对象。

这时就可以结合散列表、双向链表、跳表来实现。 使用双向链表对学生对象以score进行排序,结合跳表。在使用id作为key实现散列表。

iOS YYMemoryCache 利用散列表和双向链表实现内存缓存。 散列表的实现:直接使用系统提供CFMutableDictionaryRef