【算法与数据结构】之堆排序

优先队列

优先队列的主要操作:

  • 入队
  • 出队(取出优先级最高的元素)

例子:在N个元素中选出前M个元素?(比如,在100万个元素中选出前100名)
排序,NlogN
优先队列,NlogM(维护一个容量为M的最小堆,遍历完100万个数组之后,形成的最小堆中的M个元素就是最小的)

总共N个请求,使用普通数组或者顺序数组,最差情况O(n^2)
使用堆,O(nlogn)
 

二叉堆

最大堆两个特点:

  1. 二叉树上任何一个节点都不大于其父节点,(并不能说明,层数越高,值就越大)
  2. 是一颗完全二叉树。除了最后一层外,其他层的节点数必须是最大值,最后一层,节点数虽然可以不是最大值,但是所有节点必须集中在左侧,

用数组存储二叉堆,

节点规律:

  • 已知父节点i,则left child(i) = 2*i, right child = 2 * i + 1
  • 已知 子节点i,则父节点parent(i) = i / 2
     

二叉堆中插入元素(ShiftUp)

步骤:

  1. 将元素插入二叉堆的最底层,
  2. ShiftUp调整,将插入元素与其父节点比较,一步步向上转换(转换规则:如果该节点比其父节点还大,就往上换)
     

二叉堆中弹出元素(ShiftDown)

步骤:

  1. 把根节点弹出来,把最底下的元素拿出来放入根节点,
  2. ShiftDown调整,将根节点元素一步步向下转换(转换规则:比较左右孩子的大小,如果根节点比最大的子孩子还大,则将其与最大的孩子换位置)
     

堆排序——复杂度O(nlogn)

可以借助二叉堆来实现,思路是:

  1. 将任意数组依次insert到最大堆O(logn)(也可以使用Heapify操作,将数组形成最大堆,复杂度O(n))
  2. 再从最大堆中依次弹出,就能得到排好序的降序序列;
    (想要得到升序序列,利用最小堆即可)
     

Heapify(将数组构造成堆)——复杂度O(n)

这是一个将给定数组,形成最大堆的方法,
将n个元素逐个插入到一个空堆中,复杂度是O(nlogn),而heapify过程,复杂度只有O(n)。
具体操作是:

  1. 将元素顺序塞入最大堆中去,
  2. 对于所有的叶子节点,本身就是一个最大堆,不用进行处理;从第一个不是叶子节点的节点(从n/2的位置开始,逆序降到1) 开始, 逐级向上处理,将叶子节点的父节点当做一个最大堆,这时候只需执行ShiftDown操作,将小的根节点往下转换,一直递归到最底层结束。

【分析】:
将n个元素逐个插入到一个空堆中,算法复杂度是O(nlogn),

 

原地堆排序

步骤: 拿出最大堆顶端的最大值,与最后一个元素交换,最大元素已经归位,count–,拿出此时的顶端值,使用ShiftDown调整顶端值,使得剩余元素依然是一个最大堆,继续拿出顶端的最大值,与最后一个元素交换,使用ShiftDown调整,依次类推。

对于这个二叉堆的节点编号(根节点为0号),父节点与子节点的关系为:
parent(i) = (i -1) /2
left child(i) = 2 * i + 1
right chid(i) = 2 * i + 2

索引堆

在堆中存放的是索引,数组本身没有发生改变。比较大小的时候,比较的是data数据,但是构建索引堆的时候,堆中存放的是data数据对应的下标。元素交换的时候,也只是交换索引即可。

  • 构建一个索引堆
  • 实现索引堆的插入,弹出元素功能
  • 实现元素交换的功能(将原数组中第i个位置的元素替换成一个新的值item):需要先找到这个元素在索引堆中的位置(需要遍历索引数组,复杂度O(n)),然后分别进行ShiftUp & ShiftDown

索引堆的改进——反向查找

构造reverse数组,reverse数组中存放的是数组的下标在indexes中的位置。
使之与indexes数组互为逆序,即indexes[i] = j , reverse[j] = i
indexes[reverse[i]]=i reverse[i]本身的定义就是表示索引i在indexes中的位置,因此indexes[reverse[i]]=i
reverse[indexes[i]] = i indexes[i]表示i这个位置的索引是谁,reverse表示这个索引在indexes中的位置,

堆的应用

多路归并排序

d叉堆(d>2)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值