目的:ES6标准下的JS数据结构的一些实现代码。(作为记录和启发)

内容:二叉堆和堆排序。(未完成,待继续)

所有源码在我的Github上(如果觉得不错记得给星鼓励我哦):ES6的JavaScript数据结构实现之二叉堆和堆排序

一、基础数据结构

1、二叉堆(最小堆和最大堆;插入值(保持最小堆或最大堆结构);找到最大值或者最小值;移除最小堆的最小值(堆的根节点))

基本概念:二叉堆是一种特殊的二叉树,其有两个特性:结构特性和堆特性。结构特性是指它是一颗完全的二叉树(树的每一层都有左侧和右侧子节点(除了最后一层的叶节点),并且最后一层的叶节点尽可能都是左侧子节点)。堆特性是指二叉堆不是最小堆就是最大堆(最小堆可以快速导出树的最小值,最大堆可以快速导出树的最大值),所有的节点都大于等于(最大堆)或者小于等于(最小堆)每个它的子节点。

1.1 最小堆
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
const Compare = {
LESS_THAN: -1,
BIGGER_THAN: 1,
EQUALS: 0
};

function defaultCompare(a, b) {
if (a === b) {
return Compare.EQUALS;
}
return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN;
}

function swap(array, a, b) {
/* const temp = array[a];
array[a] = array[b];
array[b] = temp; */
[array[a], array[b]] = [array[b], array[a]];
}
function reverseCompare(compareFn) {
return (a, b) => compareFn(b, a);
}
class MinHeap {
constructor(compareFn = defaultCompare) {
this.compareFn = compareFn;
this.heap = [];
}
getLeftIndex(index) {
return 2 * index + 1;
}
getRightIndex(index) {
return 2 * index + 2;
}
getParentIndex(index) {
if (index === 0) {
return undefined;
}
return Math.floor((index - 1) / 2);
}

size() {
return this.heap.length;
}

isEmpty() {
return this.size() <= 0;
}

clear() {
this.heap = [];
}
findMinimum() {
return this.isEmpty() ? undefined : this.heap[0];
}
insert(value) {
if(value != null) {
this.heap.push(value);
const index = this.heap.length - 1;
this.siftUp(index);
return true;
}
return false;
}
siftUp(index) {
let parent = this.getParentIndex(index);
while (
index > 0
&& this.compareFn(this.heap[parent], this.heap[index]) === Compare.BIGGER_THAN
) {
swap (this.heap, parent, index );
index = parent;
parent = this.getParentIndex(index);
}
}
extract() {
if (this.isEmpty()) {
return undefined;
}
if (this.size() == 1) {
return this.heap.shift();
}
const removedValue = this.heap[0];
this.heap[0] = this.heap.pop();
this.siftDown(0);
return removedValue;
}
siftDown(index) {
let element = index;
const left = this.getLeftIndex(index);
const right = this.getRightIndex(index);
const size = this.size();
if (
left < size
&& this.compareFn(this.heap[element], this.heap[left]) === Compare.BIGGER_THAN
) {
element = left;
} else if (
right < size
&& this.compareFn(this.heap[element], this.heap[right] === Compare.BIGGER_THAN)
) {
element = right;
}
if(index !== element) {
swap(this.heap, index, element);
this.siftDown(element);
}
}
heapify(array) {
if (array) {
this.heap = array;
}
const maxIndex = Math.floor(this.size() / 2) - 1;
for (let i = 0; i <= maxIndex; i++) {
this.siftDown(i);
}
return this.heap;
}

getAsArray() {
return this.heap;
}


}

const heap = new MinHeap();
heap.insert(2);
heap.insert(3);
heap.insert(4);
heap.insert(5);
console.log(heap);
heap.insert(1);
console.log(heap);
console.log(heap.findMinimum());
heap.clear();
const heap1 = new MinHeap();
for (let i = 1; i < 10; i++) {
heap.insert(i);
}
console.log(heap);
console.log(heap.extract());
console.log(heap);

MinHeap
1.2 最大堆

把最小堆中的比较函数修改为相反的就行了,即把最小堆中的所有大于的比较换成小于的比较。

1
2
3
4
5
6
7
class MaxHeap extends MinHeap {
constructor(compareFn = defaultCompare) {
super(compareFn);
this.compareFn = compareFn;
this.compareFn = reverseCompare(compareFn);
}

二、简单应用

1、堆排序

思路:用数组创建一个最大堆;最大的值放置堆的最后一个位置;将堆的大小减一,每次执行第二个步骤直至堆的大小为1。(这样就得到升序(从最小到最大)的数组,若要数组的降序排列,则我们用最小堆。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
function heapify(array, index, heapSize, compareFn) {
let largest = index;
const left = (2 * index) + 1;
const right = (2 * index) + 2;
if (left < heapSize && compareFn(array[left], array[index]) > 0) {
largest = left;
}
if (right < heapSize && compareFn(array[right], array[largest]) > 0) {
largest = right;
}
if (largest !== index) {
swap(array, index, largest);
heapify(array, largest, heapSize, compareFn);
}
}

function buildMaxHeap(array, compareFn) {
for (let i = Math.floor(array.length / 2); i >= 0; i -= 1) {
heapify(array, i, array.length, compareFn);
}
return array;
}

function heapSort(array = [], compareFn = defaultCompare) {
let heapSize = array.length;
buildMaxHeap(array, compareFn);
while (heapSize > 1) {
swap(array, 0, --heapSize);
heapify(array, 0, heapSize, compareFn);
}
return array;
}

const heapSort1 = new heapSort();
const array = [7, 6, 3, 5, 4, 1, 2];

console.log('Before sorting: ', array);
console.log('After sorting: ', heapSort(array));