-
堆
- buf + heapSize + limit(一般来说有,只用来判满)
- 是一颗完全二叉树,要么是满二叉树,要么是从左往右依此变满
- 完全二叉树的实现,数组从0出发的连续一段构成完全二叉树,左孩子2n+1,右孩子2n+2,父(n-1)/2,0算出来的父亲是自己
- 堆分为大根堆和小根堆
- 大根堆本身以及每颗子树最大值是头节点的值
利用数组生成大根堆,从heapsize=0开始,每个数新进来时,放在下标heapsize的地方
- heap insert(arr, i):要插入的数已经放置在数组的i=heapsize处了
- 和自己的父节点进行比较,如果大了就要交换,不断和父比较,不断往上窜
- 从而能保证每次加入一个数,保持一个大根堆
- 可以只写一个while大于自己的父亲,但实际上表示了两个条件
- 小根堆的扩容
- 成倍扩容,每次扩容需要进行复杂度O(N)的复制
- 扩容的次数时logN水平的
- 加上扩容的代价,分摊到每一个树上O(NlogN)/N = O(logN),加入一个数的复杂度仍然是logN水平
从大根堆中取出一个最大的数
把最后一个数换到第一个位置,heapsize-1,最后一个位置已经不计入堆了
- heapify(arr,index,heapsize)
- 与左孩子和右孩子比较,将较大的孩子交换上来,交换下去的继续向下比较,不再小于时停止
- 需要一个heapsize变量,来确定是否还有孩子
- 当大根堆中间某个位置的值发生了改变
- 如果变小了,从这个位置开始往下进行一个heapify
- 如果变大了,从这个位置开始网上进行一个heapinsert
- 堆的深度是logN
- 因为有这么多层,用户进行新增一个数或者取出一个数的复杂度都是logN
- 优先级队列
- 不是队列而是堆,使用的时候像队列而已
- 不支持已经形成堆结构的数组里面,去修改特定位置的数
- 如果只需要加入弹出,使用现成的就好,要修改特定位置,使用较小的代价就调整好,需要自己实现
-
堆排序:O(NlogN),O(1)
-
输入是一个数组
-
先让整个数组构成一个大根堆,从heapsize=0开始,不断向后看,相当于不断插入新的数,不断heapinsert
- 当一次性拥有了所有数字时,其实有复杂度更低的做法,对数组逆序,每个位置作heapify
- 这样子,所有的叶节点实际上都不用操作,只有O(1)复杂度看一眼,而叶节点有n/2个
- 倒数第二层n/4个节点,O(2)复杂度,依此递推
- T(N) = N/2 + N/4 2 + N/8 3 + ……
- 构造2T(n),错项相减,生成等比数列,最后得到复杂度O(N)
-
然后将第一个位置和最后一个位置的数做交换,heapsize–,相当于取出了最大的数,放在了数组最后面(堆外面)
-
进行heapify,调整完之后,重复上一步骤,while(heapsize>0)
-
额外空间复杂度O(1),没有任何的递归过程,时间复杂度O(NlogN)
-
堆排序的应用:几乎有序的数组进行排序(移动最多k位)O(Nlogk)复杂度
- 准备一个小根堆(直接用优先队列就好了),遍历数组前k+1个数,
- 弹出小根堆的最小数,一定在0位置上,
- 接着放入一个数,弹出一个数
- 最后数组中的数全部放完,将小根堆中的数依此弹出即可
-
-
比较器的使用
-
实质上时重载比较运算符,配合stl,java现成函数使用
-
一般现成排序默认从小到大
-
比较器的返回值含义
- 返回负数,第一个参数排在前面
- 返回正数,第二个参数排在前面
- 返回0,谁排前面无所谓
-
如果数字
- 降序返回o1-o2即可
- 升序返回o2-o1即可
-
比较器还可以用在有排序含义中的结构中
- 如优先队列,默认时小根堆,定义比较器返回第二个数减第一个数,就生成大根堆
-
算法系列05——堆和比较器
最新推荐文章于 2024-10-06 20:10:02 发布
堆是一种特殊的完全二叉树,分为大根堆和小根堆。大根堆保证每个节点的值大于或等于其子节点,反之亦然。插入和删除操作的时间复杂度为O(logN)。堆排序算法通过构建和调整堆来实现排序,复杂度为O(NlogN)。优先级队列常基于堆实现,支持插入和删除操作,但不支持直接修改特定位置。比较器在排序和优先级队列中用于自定义元素的比较规则。
摘要由CSDN通过智能技术生成