堆结构的运用

  堆通常用来表示元素集合。小根堆的任何父结点的值都小于或等于其子结点的值。最底层的叶结点尽可能地靠左分布,树中不存在空闲的位置。堆可以用二叉树或一维数组来表示。用数组x[1...n]表示时,value(i)=x[i], leftchild(i)=2*i, rightchild(i)=2*i+1, parent(i)=i/2,根为x[1]。我们可能把堆定义为heap(t,u),对任意的2t<=i<=u有x[i/2]<=x[i]。
  (1)堆的向上筛选:当x[1...n-1]是堆时,在x[n]中放置一个任意的元素后,x[1...n]可能不是堆,需要向上筛选(通过交换该结点与其父结点来实现),以建成堆heap(1,n)。

  因为堆具有logn层,故运行时间为O(logn)。
  (2)堆的向下筛选:当x[1...n]是堆时,给x[1]分配一个新值后x[2...n]仍是堆heap(2,n),但x[1...n]可能不再是堆,需要向下筛选(通过交换该结点与子结点),重新建成堆heap(1,n)。

  算法的运行时间为O(logn)。
  (3)堆排序:我们采用大根堆,只要把上面算法中的<和>运算互换即可。先扫描元素,通过不断地向上筛选来建立堆heap(1,n)。接着利用堆来建立有序序列。前段为未排序部分,后段为已排序部分。每建一次堆,堆顶就是未排序部分的最大元素,把它与未排序部分的末尾元素交换,这样已排序部分长度就增1。由于堆顶分配了一个新值,重新向下筛选以建成新堆。

  算法使用了n-1次siftup和n-1次siftdown,故运行时间为O(nlogn)。
  (4)优先级队列的实现:优先级队列的insert在集合中插入一个新元素,extractmin删除集合中最小的元素。当然我们可以用数组或链表之类的线性结构来实现,但用堆结构实现更高效。用x[1...n]表示n元集合,insert函数插入新元素时,n加1并将新元素放在x[n]处,由于满足heap(1,n-1),故向上筛选即可调整成新堆heap(1,n)。对extractmin函数,只要将x[n]移动到x[1],n减1,就删除了最小元x[1]。由于仍满足heap(2,n),故向下筛选即可调整成新堆heap(1,n)。两个函数的运行时间均为O(logn)。为简便,实现时我们集中于算法本身,没有考虑错误处理、资源析构、拷贝构造等问题。标准模板库中提供了优先级队列结构priority_queue。

  (5)堆结构的一些应用例子:
  构造哈夫曼编码:选择集合中的两个最小结点,将其归并为一个新结点。这可通过两次extractmin调用和一次insert调用来实现。如果输入是有序,则可在线性时间内完成。
  计算大型浮点数集合的和:如果简单地把较小和较大的浮点数相加可能会丢失精度。较好的办法是每次把集合中最小的两个数相加,类似于构造哈夫曼编码的过程。
  在存有10亿个数的文件中找出最大的100万个数:用一个含有一百万个元素的堆来存放结果,并采用多趟策略。先读取前100万个数到堆数组中,并建成堆,堆顶为最小元。后续每读一个数就跟堆顶元素比较,若小于堆顶元,就什么也不做;若大于堆顶元,就用这个数替换掉堆顶元素,并向下筛选重新调整成堆。然后读下一个数。
  将多个较小的有序文件归并为一个较大的文件:用堆表示每个文件中的下一个元素,从而实现对有序文件的归并。迭代步骤从堆中选出最小的元素,将其后继插入堆中。n个文件中下一个待输出的元素可以在O(logn)时间内选出。
  关键算法设计思想:堆结构、优先级队列、排序策略。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值