数据结构总结(一):一种特殊的有序队列

  遇到过一种比较特殊的队列,以前我习惯叫它“双端队列”,可能是当时的误解,先假想一下如下的情况:

有一堆元素,每个元素有一个关键值key,一个代表位置的pos。对于一个给定的位置p,我要找与这个位置距离不超过k的最小(大)的值。但是还有一个重要限制,这堆元素得一个一个处理和查询,先处理的元素的pos必须比后处理的元素的pos要小。就是说,第一个元素处理,第二个元素处理。。。第i个元素处理,这时候如果要查询,只能查询跟第i个元素距离为k的最小(大)的前面处理过的元素,我姑且定位为这种查询为“立即查询”吧。这里有点不好理解,或者说,这么苛刻的条件,这种结构会有什么用武之地,慢慢来,后面你就会明白。

 

  我继续沿用“双端队列”来称呼我所要表达的这种结构,“双端队列”支持两种操作,一是插入,二是出队列,出来的这个元素是和给定的一个pos值不超过k距离的最小(大)的元素。

 

下面以支持弹出最小元素为例,最大类似

1.基本结构:

 

令元素为E(key,pos),表示关键字为key,位置为pos的元素;令查询Q(pos,k),查询前面出现的,跟pos位置不超过k的最小元素。

 

2.插入操作:

队列中将维护一个有序单调非降的序列,当插入元素E(key, pos)时,按key二分查找,查找的落点将落在>key的第一个,如:

que(key):1 2 3 4 7

如果插入3,那么落点是4这个位置,然后修改队尾指针r,使得队列调整为que(key): 1 2 3 3,也就是说4,7都被删除了。为什么呢?因为我后面如果有查询(出队列),我要找最小值,而且,根据前面我们说的必须条件,前面先处理的元素的pos要比我当前小,也就是说4,7的pos比后面的3小,故后面的查询Q(pos,k),无论是pos还是key,4,7比新来的3都没有优势,不可能是他们,所以删除也无妨。

 

这里f是队列的头位置,而r是队列的尾位置的下一个。

 

3.出队列操作(查询)

出队列很简单,因为已经是一个有序非降的序列,所以越前面的元素越小,但是,可能其距离不满足要求。这时有个减小队列的维护,如果前面的元素不满足条件,那么这些元素都可以从队列中删除了,因为后面的查询操作将更加不能满足距离要求(还记得必须条件吗)。

 

 

我将给一个列子来说明这个“双端队列”的一个应用:

http://acm.pku.edu.cn/JudgeOnline/problem?id=2823

这道题目的意思是:给定一个数组,如[1 3 -1 -3 5 3 6 7],给定一个窗口m=3,窗口从左到又移动,输出每次窗口中的最小最大值。

该例子

[1 3 -1] -3 5 3 6 7,最小-1,最大3

1 [3 -1 -3] 5 3 6 7,最小-3,最大3

等等。。。

其实就是每次查询跟第i个元素距离不超过m的最小(大),在这里每个元素的key是其值,pos是出现的下标。满足pos越后面越大,而且每次都是“立即查询”。故可用“双端队列”求解。

其他在一些DP类中,也很有可能用到它来做优化,08年北京赛区Regional中就有一个又此结构优化的DP的题目,具体忘记了。

下面是pku2828的代码:

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值