我们上一篇文章,对堆进行了处理,shift up、shift down等操作。
这篇文章来介绍一下如何给定一个数组,生成一个最大堆?
下图是一个随机的数组,蓝色的部分表示的是叶子结点。
思考:
- 将叶子节点的最后一个(值:62;索引:10)与它的父节点(index/2)进行比较。
- 做shift down操作。
- 这样从索引值5开始,到它的子节点之后,就满足了最大堆的形式。
- 此时我们的数组就变成了如下图:
思考:
- 如果索引10,以及他的父节点索引5,已经满足最大堆条件。
- 那它的索引9和8的父节点是不是也可以进行shift down的操作,来达到最大堆的要求?
- 答案是肯定的。
- 那我们的索引6和7的父节点呢?索引4和5的父节点呢?索引2和3的父节点呢?
- 我们发现,经过不断的shift down的操作,我们最终将一个随机的数组转换成了最大堆。
- 但是要注意:当我们算索引为4和5的父节点的时候,索引2到子节点索引4和5为最大堆之后,4这个节点的子节点索引8和9还要继续进行运算,或者是5的子节点10还要进行运算,不会出现4和5都需要shift down操作的情况。
看下图对比上图,方便仔细思考:
// 最大堆排序
// 给定一个数组,将这个数组形成堆的形式
// Heapify
let arr = ["", 15, 17, 19, 13, 22, 16, 28, 30, 41, 62]
let arrLength = arr.length
function swap(arr, leftIndex, rightIndex) {
[arr[leftIndex], arr[rightIndex]] = [arr[rightIndex], arr[leftIndex]]
}
function shiftDown(arr, k) {
while (k * 2 <= arr.length) {
let j = k * 2
if (j + 1 <= arr.length && arr[j + 1] > arr[j]) {
j+=1;
}
if (!arr[j] || arr[k] > arr[j]) {
break;
}
swap(arr, k, j)
k = j;
}
return arr;
}
function heapify(arr, arrLength) {
for (let i = parseInt((arrLength - 1) / 2); i >= 1; i--) {
shiftDown(arr, i)
}
return arr;
}
console.log(heapify(arr, arrLength))
最大堆排序
虽然上一篇文章已经介绍过如何排序,但是避免大家再去翻找,我就再来实现一下。
以下是实现,大概的思路在备注中,详细的思路不写在这里了,想看还是去上一篇文章里面找吧。感谢大家支持!!!
因为生成最大堆的时候不需要对数组进行splice,可是在排序的时候还需要,而一个shiftDownd函数满足两种情况,并且返回值不同,所以要进行封装判断。
// 最大堆排序
// 给定一个数组,将这个数组形成堆的形式
// Heapify
let arr = ["", 15, 17, 19, 13, 22, 16, 28, 30, 41, 62]
let arrLength = arr.length
// 排序,交换位置
function swap(arr, leftIndex, rightIndex) {
[arr[leftIndex], arr[rightIndex]] = [arr[rightIndex], arr[leftIndex]]
}
// 将check封装,arr数组在排序时才需要切割
function check(arr){
let arraySplice = arr.splice(arr.length-1, 1)
let arrSpliceMax = arr.splice(1, 1)
arr.splice(1, 0, arraySplice[0])
return arrSpliceMax;
}
function shiftDown(arr, k, flag) {
let arraySplice = [];
if(flag){
arraySplice.push(...check(arr))
}
while (k * 2 <= arr.length) {
let j = k * 2
if (j + 1 <= arr.length && arr[j + 1] > arr[j]) {
j += 1;
}
if (!arr[j] || arr[k] > arr[j]) {
break;
}
swap(arr, k, j)
k = j;
}
let arrMax = !flag? arr : arraySplice
return arrMax
}
// 取最后一个子叶节点的父节点索引值
// 进行shift down
function heapify(arr, arrLength) {
for (let i = parseInt((arrLength - 1) / 2); i >= 1; i--) {
shiftDown(arr, i, false)
}
return arr;
}
let arrayHeap = heapify(arr, arrLength);
console.log(arrayHeap)
// 排序
// 思路是取出最大值,然后将最后值放在第一位(index=1的位置)
// 继续
shift downfunction heapSort(arr) {
let array = []
for (let i = 1; i < arr.length; i++) {
array.push(...shiftDown(arr, 1, true))
}
arr.splice(arr[0], 1)
array = [...array, ...arr]
return array
}
console.log(heapSort(arrayHeap))
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!