首先标题中提到的复杂度指的是时间复杂度。
双向链表的增加节点(首或尾)、删除节点(提供指针参数)、修改节点(提供指针参数)、插入节点(提供指针参数,和元素)的复杂都容易达到O(1),也就是常量级别。它是一个顺序容器,可以把它当做队列或栈来用。
但是如果给定一个元素值参数,而不是指针参数,想知道双向列表里面有没有这个元素(或者需要找到这个元素的指针并进行修改其值),那么只能是顺序的遍历,那么时间复杂度是O(N),即他会随着元素的个数线性增长,有些时候这个不可接受的。
在特定的情况,我们可以借助具有增删改查复杂度都为O(lg)的map,来结合双向列表一起使用,使得容器既具有双向列表的“O(1)复杂度增删”性能,也具有O(lg)复杂度的查找性能。具体操作是,把双向列表中的元素做key,把元素的指针做value,用这些<key,value>做map的内容。
说到这里要提一下,这样的容器并不通用,只是适合于某些场景—-当双向列表里面的元素不重复的时候,这个很关键。如果不符合,那就没必要这么复杂的搞了。下面举一个符合的应用场景。
交易市场上源源不断的推送来股票报价,明显股票代码是一个唯一的标识,由于发送给客户的速度慢,需要一个队列(用双向链表)保存这些报价,但如果同一只股票新的报价都来了,旧的报价就考虑被删掉,并且把新的报价放到队列最后面。在这个应用场景中,用到了双向连接的结尾添加、首部删除、以及元素删除功能。因为删除的关键字是元素,而不是代表了节点位置的指针,所以要删除,必需要先进行顺序查找。这个应用场景中,业务需求是,报价是可以丢掉一部分,但是推送的报价的先后顺序是不能乱的。
其他问题:
1、关于空间复杂度,明显地空间占用增多了,除了队列保存必要的N个元素,还要在map中保存每个元素的指针。
2、保存指针的map也可以考虑换成hash表,那就有可能Amort. O(1)的查找复杂度。
3、欢迎反馈:), 提疑问或建议~
—————————————————————————-
今天偶然看到Java中有类似功能的容器了,如ListOrderedMap、LinkedHashMap,有空可以测试测试他们的复杂度,以及查看它们的源代码来学习。
稍晚点有发现了java中还有方便使用的BidiMap,突然觉得Java实在是众人的结晶呀,我也要多学习Java,尽早跟“熟悉”二字接近点。