heap.js
3.1 KB
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
/**
* @fileoverview Heap Sort 実装. ハフマン符号化で使用する.
*/
goog.provide('Zlib.Heap');
goog.require('USE_TYPEDARRAY');
goog.scope(function() {
/**
* カスタムハフマン符号で使用するヒープ実装
* @param {number} length ヒープサイズ.
* @constructor
*/
Zlib.Heap = function(length) {
this.buffer = new (USE_TYPEDARRAY ? Uint16Array : Array)(length * 2);
this.length = 0;
};
/**
* 親ノードの index 取得
* @param {number} index 子ノードの index.
* @return {number} 親ノードの index.
*
*/
Zlib.Heap.prototype.getParent = function(index) {
return ((index - 2) / 4 | 0) * 2;
};
/**
* 子ノードの index 取得
* @param {number} index 親ノードの index.
* @return {number} 子ノードの index.
*/
Zlib.Heap.prototype.getChild = function(index) {
return 2 * index + 2;
};
/**
* Heap に値を追加する
* @param {number} index キー index.
* @param {number} value 値.
* @return {number} 現在のヒープ長.
*/
Zlib.Heap.prototype.push = function(index, value) {
var current, parent,
heap = this.buffer,
swap;
current = this.length;
heap[this.length++] = value;
heap[this.length++] = index;
// ルートノードにたどり着くまで入れ替えを試みる
while (current > 0) {
parent = this.getParent(current);
// 親ノードと比較して親の方が小さければ入れ替える
if (heap[current] > heap[parent]) {
swap = heap[current];
heap[current] = heap[parent];
heap[parent] = swap;
swap = heap[current + 1];
heap[current + 1] = heap[parent + 1];
heap[parent + 1] = swap;
current = parent;
// 入れ替えが必要なくなったらそこで抜ける
} else {
break;
}
}
return this.length;
};
/**
* Heapから一番大きい値を返す
* @return {{index: number, value: number, length: number}} {index: キーindex,
* value: 値, length: ヒープ長} の Object.
*/
Zlib.Heap.prototype.pop = function() {
var index, value,
heap = this.buffer, swap,
current, parent;
value = heap[0];
index = heap[1];
// 後ろから値を取る
this.length -= 2;
heap[0] = heap[this.length];
heap[1] = heap[this.length + 1];
parent = 0;
// ルートノードから下がっていく
while (true) {
current = this.getChild(parent);
// 範囲チェック
if (current >= this.length) {
break;
}
// 隣のノードと比較して、隣の方が値が大きければ隣を現在ノードとして選択
if (current + 2 < this.length && heap[current + 2] > heap[current]) {
current += 2;
}
// 親ノードと比較して親の方が小さい場合は入れ替える
if (heap[current] > heap[parent]) {
swap = heap[parent];
heap[parent] = heap[current];
heap[current] = swap;
swap = heap[parent + 1];
heap[parent + 1] = heap[current + 1];
heap[current + 1] = swap;
} else {
break;
}
parent = current;
}
return {index: index, value: value, length: this.length};
};
// end of scope
});
/* vim:set expandtab ts=2 sw=2 tw=80: */