堆和堆排序:爲什麼說堆排序沒有快速排序快?
堆排序交互數據次數比快排的多
堆:
- 堆是一個完全二叉樹;
- 堆中的每一個節點的值都必須大於等於(或小於等於)其子樹中每個節點的值。
大頂堆,根節點最大
小頂堆,跟節點最小
/*
* @Author: HotSuitor
* @Date: 2020-03-19 16:01:22
* @LastEditors: hs
* @LastEditTime: 2020-03-19 22:44:45
* @Description: [email protected]
*/
// 堆
const heap = [undefined, 33, 27, 21, 16, 13, 15, 9, 5, 6, 7, 8, 1, 2];
class Heap {
constructor(arr, size) {
this.heapArray = arr || [];
this.size = size + 1 || 300;
}
// 根節點索引=1,左子節點=2*i,右子節點=2*i+1, i=層數
insert(data) {
let len = this.heapArray.length;
if (len >= this.size) {
console.log("堆滿了");
return; // 堆滿了
}
if (len === 0) {
this.heapArray.splice(0, 0, undefined, data);
return;
}
this.heapArray.push(data);
let currentIndex = this.heapArray.length - 1;
let i; // 層數,從0開始
let parentIndex;
//! 奇數->跟、右節點,偶數->左節點
parentIndex = currentIndex % 2 ? (currentIndex - 1) / 2 : currentIndex / 2; // 父節點的索引
// 自下往上堆化
while (
parentIndex > 0 &&
this.heapArray[currentIndex] > this.heapArray[parentIndex]
) {
this.swap(this.heapArray, currentIndex, parentIndex);
currentIndex = parentIndex;
parentIndex =
currentIndex % 2 ? (currentIndex - 1) / 2 : currentIndex / 2; // 父節點的索引
}
}
// 刪除堆頂元素
deleteTop(data) {
let len = this.heapArray.length;
if (len <= 2) return this.heapArray;
/**最後一個與第一個元素互換位置
* 再自頂而下堆化
*/
this.swap(this.heapArray, 1, len - 1);
this.heapArray.pop();
let i = 1;
while (
i * 2 < this.heapArray.length &&
this.heapArray[i] < this.heapArray[i * 2]
) {
this.swap(this.heapArray, i, i * 2);
i = i * 2;
}
}
scan() {
return this.heapArray;
}
swap(arr, i, j) {
let tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
class Heap2 {
constructor(capacity) {
this.arr = new Array(capacity + 1); // 數組下標從1開始
this.n = capacity; // 堆可以存儲的最大數據個數
this.count = 0; // 堆中已存儲的數據個數
}
// 建堆
static buildHeap(arr) {
if (!Array.isArray(arr)) return;
let n = arr.length - 1; // 堆元素個數
// 從第i個節點開始從上往下堆化,子節點不需要比較,所以向下取整
let i = Math.floor(n / 2);
for (; i >= 1; --i) {
Heap2.heapify(arr, n, i);
}
return arr;
}
static heapify(arr, n, i) {
while (true) {
let maxPox = i;
// 左子節點比父節點大
if (i * 2 <= n && arr[i] < arr[i * 2]) maxPox = i * 2;
// 右節點比左節點大
if (i * 2 + 1 <= n && arr[maxPox] < arr[i * 2 + 1]) maxPox = i * 2 + 1;
if (maxPox === i) break;
// 交互父子節點
Heap2.swap(arr, i, maxPox);
i = maxPox;
}
}
insert(data) {
if (this.count >= this.n) return; // 堆滿了
this.count++;
this.arr[this.count] = data;
let i = this.count;
// 自下而上堆化
while (i / 2 > 0 && this.arr[i] > this.arr[i / 2]) {
this.swap(this.arr, i, i / 2);
i = i / 2;
}
}
static deleteTop(arr) {
if (arr.length <= 1) return;
Heap2.swap(arr, 1, arr.length - 1);
let result = arr.pop();
let i = 1;
while (true) {
let maxPox = i;
// 左節點
if (i * 2 < arr.length && arr[i] < arr[i * 2]) maxPox = i * 2;
if (i * 2 + 1 < arr.length && arr[maxPox] < arr[i * 2 + 1])
maxPox = i * 2 + 1;
if (maxPox === i) break;
Heap2.swap(arr, i, maxPox);
i = maxPox;
}
return result;
}
scan() {
return this.arr;
}
static swap(arr, i, j) {
let tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
swap(arr, i, j) {
let tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
// 堆排序
static sort(arr) {
let i = arr.length - 1; // 排序的索引
let result = new Array(arr.length);
for (; i >= 1; i--) {
let maxValue = Heap2.deleteTop(arr);
result[i] = maxValue;
}
return result;
}
}
// let heap2 = new Heap(heap);
// heap2.insert(22);
// heap2.insert(23);
// console.log(heap2.scan());
// heap2.deleteTop();
// heap2.deleteTop();
// console.log(heap2.scan());
// let heap3 = new Heap([], 5);
// heap3.insert(23);
// heap3.insert(27);
// heap3.insert(33);
// heap3.insert(45);
// heap3.insert(22);
// console.log(heap3.scan());
// heap3.deleteTop();
// console.log(heap3.scan());
// let heap4 = new Heap2(5);
// heap4.insert(33);
// heap4.insert(23);
// heap4.insert(45);
// heap4.insert(22);
// heap4.insert(7);
// console.log(heap4.scan());
let arr1 = [, 3, 44, 23, 18, 39, 26, 77];
let arr2 = [...arr1];
let arr1Heap = Heap2.buildHeap(arr2);
console.log("arr1", arr1);
console.log("arr1Heap", arr1Heap);
console.log("heapSort", Heap2.sort(arr1Heap));