数据结构与算法(一)——散列表的应用

一、java容器LinkedHashMap

LinkedHashMap是在普通HashMap的基础上新增了Linked功能,那Linked是什么呢?

Linked表示当我们将key-value对加入到map容器中时,会按照添加的先后顺序进行排序。也就是说,当执行以下代码时,

// 10表示初始大小,0,75表示装载因子,true表示按照访问时间顺序
Map<Integer, String> map = new LinkedHashMap<>(10, 0.75f, true);
map.put(2,"bb");
map.put(1,"aa");
map.put(3,"cc");

for(Map.Entry entry : m.entrySet()){
  System.out.println(entry.getKey());
}

打印出来的顺序就是2,1,3。

这是由于LinkedHashMap底层不仅使用了散列表便于快速存取元素,还使用了双向链表。将各个元素按照插入时间的先后顺序组织成双向链表,这就使得LinkedHashMap支持按照插入顺序遍历元素。

在这里插入图片描述

这里,散列表部分是key-value映射,而双向链表部分,则对各元素按照插入时间的先后顺序进行了排序。节点的pre和next域属于双向链表,分别指向双向链表中节点的前驱和后继。而hnext域则属于散列表,用拉链法解决冲突。

下面再来改一下这段代码。

// 10表示初始大小,0,75表示装载因子,true表示按照访问时间顺序
Map<Integer, String> map = new LinkedHashMap<>(10, 0.75f, true);
map.put(2,"bb");
map.put(1,"aa");
map.put(3,"cc");

map.put(1,"dd");
map.get(2);

for(Map.Entry entry : m.entrySet()){
  System.out.println(entry.getKey());
}

这样,得到的结果是3,1,2。

原因是,LinkedHashMap还支持按照访问时间的顺序进行遍历,在map.put(1,“dd”)时,使得key为1的键值对被访问,在map.get(2),使得key为2的键值对被访问。所以,按照访问的时间先后顺序是3,1,2。

处理方法实际上用到了LRU原则(最近最少使用原则),首先设定链表头部为最先访问的节点,尾部为最新访问的节点,头尾各有指针指向。当查询1个节点时,如果节点不在链表中,则将其加入到链表尾部;如果节点在链表中,则将其移动到链表的尾部。在构建LinkedHashMap时指定按照访问时间顺序为true,就可以按照访问顺序遍历了。

注意:这里并不适合使用单链表。原因是,当我们使用散列表以O(1)复杂度查找到目标节点时,如果使用了单链表,则必须再以O(n)复杂度获取到该目标节点的前驱节点,才可以删除该目标节点。而如果使用双链表,可以直接以O(1)复杂度删除。

二、Redis有序集合

在有序集合中,每个成员对象有两个重要属性,key(键值)和score(分值),一般会通过key来查找数据,也会用score值来查数据。比如,支付宝的每个用户都有1个用户id(即key)、姓名,每个用户还有自己的支付宝积分(即score)。

对用户对象的操作包括:

①添加一个用户;

②按id删除一个用户;

③按id查找一个用户;

④按照积分进行范围查找,比如查找分值在[100,200]的所有用户;

⑤按照积分对用户进行排序。

那么该如何高效地实现这些方法呢?

借用 LinkedHashMap 的实现原则,使用散列表+双向链表的方式。

  1. 首先,前三个操作可以看做是使用到了key,那么就可以按照键值构建散列表,这样时间复杂度为O(1)。
  2. 然后,对于按照积分score对成员对象进行范围查找、排序等操作,可以按score值从小到大的顺序将对象组织成双向链表。

然而,用双向链表查找一个对象的时间复杂度为O(n),可以更高效一点吗?

由于该双链表是有序的,那么就可以借助有序数组的“二分法”思想,对链表进行二分查找,也就是所谓的跳表。

跳表

在使用跳表后,范围查找的时间复杂度为O(logn)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值