目录
前言
“堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。”
堆排序 时间复杂度O(n*log n) 空间复杂度O(1)
可以自由添加数据,但取出数据时要从最小值开始按顺序取出。
结点的排列顺序为从上到下,同一行里则为从左到右。
子结点必定大于父结点。(小顶堆) 父结点必定大于子结点。(大顶堆)
往堆中添加数据时,为了遵守这条规则,一般会把新数据放在最下面一行靠左的位置。
当最下面一行里没有多余空间时,
就再往下另起一行,把数据加在这一行的最右端。
一、执行流程
1对序列进行原地建堆(heapify) 如果父元素改变位置就要递归了 恢复堆的规则
2递归重复 执行以下操作.直到堆的元素数量为1
交换堆顶元素与尾元素
堆的元素数量减1
堆数组索引[0]进行heapify操作
二、代码实现
//大顶堆
// let arr = [1, 4, 6, 5, 3, 7, 2]
// let arr = [80, 43, 50, 21, 38, 14]
// let arr = [7, 5, 1, 6, 4, 2, 3]
// let arr = [50, 21, 80, 43, 38, 14]
// let arr = [7,6,5,4,3,2,1]
// let arr = [1,5,4,3,6,7,2]
// let arr = [1,1,2,3,3,2,2]
// let arr = [1,1,2,3,22]
let arr = [9,8,7,6,5,0,1,2,4,3]
heap_sort(arr, arr.length)
console.log(arr)
//建堆 制定堆的规则 运行是从下面开始的 这里只是制定规则
// arr : 当前数组
// n : 数组的长度 因为会发生变化所以要接一下
// i : 让这个节点 符合堆的规则 这是因为后期传来的值会导致堆的规则发生变化
function heapify(arr, n, i) {
let temp; //用来交换位置
let largest = i //代表父节点
let lson = i * 2 + 1 // 左孩子节点
let rson = i * 2 + 2 // 右孩子节点
//不能超出数组长度 会浪费时间 而且后期不能让他跟最后一个元素(n-1)比较
// 因为最大的被换位置到了最后面,所以不能让他们比较
if (lson < n && arr[largest] < arr[lson]) {
largest = lson
}
if (rson < n && arr[largest] < arr[rson]) {
largest = rson
}
//父节点如果不是以前的i说明有一个孩子比他大,所以要换位置
if (largest != i) {
temp = arr[i]
arr[i] = arr[largest]
arr[largest] = temp
//但是换位置就发现,破坏了堆的规则 所以我们又要执行一次
//arr : 数组 n : 数组长度 要维护父节点所以要对父节传进去换位置
heapify(arr, n - 1, largest)
}
}
// 上面是制定规则 当是运行还是从这里开始
//我们只需要二个参数 不需要i 因为i的节点的维护交给heapify
//我们只要传arr数组和长度就行
function heap_sort(arr, n) {
let temp = null//交换位置
// Math.floor(arr.length / 2) - 1代表最后一个父节点 因为是从最后一个父节点开始比较的
// let arr = [7, 3, 4, 2, 5, 1, 6] length 7 / 2 - 1 = 数组索引2
// i >= 0 是因为他还有索引为0的父节点也是大顶堆的最大数
//i -- 是因为先从右开始比较维护在从左 最后一个索引0就是大顶
// 这个for循环执行完就代表堆的规则执行完了
for (let i = Math.floor(arr.length / 2) - 1; i >= 0; i--) {
// 代码是在这里运行的 上面的heapify虽然写了但是堆还是没有制定规则 只有这里执行完才制定规则
heapify(arr, n, i)
}
//最复杂的地方
for (let i = n - 1; i > 0; i--) {
// 这个地方实现的效果是 最大的与最后面的换位置
temp = arr[0]
arr[0] = arr[i]
arr[i] = temp
// i 代表数组长度必须要传给heapify的长度
//而且这个i每次必须-- 不然在heapify里面执行的时候就会动最后的元素
// 这个0就是因为最大跟的跟最后面的换位置了
// 然后最后面的就变成了数组的0位 然后他又不是最大的所以又要重新制定规则
heapify(arr, i, 0)
}
}
三、图片演示
总结
基本思想:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。