Skip to content

Commit 17e1ec5

Browse files
authored
Merge pull request #664 from BeatsuDev/perf/moveNode-optimization
Optimize `_sortNodeUp/Down` methods and `_moveNode` method (11x improvement)
2 parents c43aed3 + 877e37f commit 17e1ec5

File tree

12 files changed

+336
-281
lines changed

12 files changed

+336
-281
lines changed

dist/heap-js.es5.js

Lines changed: 70 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,7 @@ var HeapAsync = /** @class */ (function () {
643643
if (array) {
644644
this.heapArray = __spreadArray$1([], __read$1(array), false);
645645
}
646-
i = Math.floor(this.heapArray.length);
646+
i = Math.floor(this.heapArray.length / 2);
647647
_a.label = 1;
648648
case 1:
649649
if (!(i >= 0)) return [3 /*break*/, 4];
@@ -1023,53 +1023,52 @@ var HeapAsync = /** @class */ (function () {
10231023
* @param {Number} k Another node index
10241024
*/
10251025
HeapAsync.prototype._moveNode = function (j, k) {
1026-
var _a;
1027-
_a = __read$1([this.heapArray[k], this.heapArray[j]], 2), this.heapArray[j] = _a[0], this.heapArray[k] = _a[1];
1026+
var temp = this.heapArray[j];
1027+
this.heapArray[j] = this.heapArray[k];
1028+
this.heapArray[k] = temp;
10281029
};
10291030
/**
10301031
* Move a node down the tree (to the leaves) to find a place where the heap is sorted.
10311032
* @param {Number} i Index of the node
10321033
*/
10331034
HeapAsync.prototype._sortNodeDown = function (i) {
10341035
return __awaiter(this, void 0, void 0, function () {
1035-
var length, left, right, best, _a, _b;
1036-
return __generator$1(this, function (_c) {
1037-
switch (_c.label) {
1036+
var length, originalIndex, value, left, right, best, _a;
1037+
return __generator$1(this, function (_b) {
1038+
switch (_b.label) {
10381039
case 0:
10391040
length = this.heapArray.length;
1040-
_c.label = 1;
1041+
originalIndex = i;
1042+
value = this.heapArray[i];
1043+
_b.label = 1;
10411044
case 1:
10421045
left = 2 * i + 1;
10431046
right = left + 1;
1044-
best = i;
1045-
_a = left < length;
1046-
if (!_a) return [3 /*break*/, 3];
1047-
return [4 /*yield*/, this.compare(this.heapArray[left], this.heapArray[best])];
1047+
if (left >= length)
1048+
return [3 /*break*/, 5];
1049+
_a = right >= length;
1050+
if (_a) return [3 /*break*/, 3];
1051+
return [4 /*yield*/, this.compare(this.heapArray[left], this.heapArray[right])];
10481052
case 2:
1049-
_a = (_c.sent()) < 0;
1050-
_c.label = 3;
1053+
_a = (_b.sent()) < 0;
1054+
_b.label = 3;
10511055
case 3:
1052-
if (_a) {
1053-
best = left;
1054-
}
1055-
_b = right < length;
1056-
if (!_b) return [3 /*break*/, 5];
1057-
return [4 /*yield*/, this.compare(this.heapArray[right], this.heapArray[best])];
1056+
best = _a ? left
1057+
: right;
1058+
return [4 /*yield*/, this.compare(this.heapArray[best], value)];
10581059
case 4:
1059-
_b = (_c.sent()) < 0;
1060-
_c.label = 5;
1061-
case 5:
1062-
if (_b) {
1063-
best = right;
1060+
if ((_b.sent()) < 0) {
1061+
this.heapArray[i] = this.heapArray[best];
1062+
i = best;
10641063
}
1065-
if (best === i)
1066-
return [3 /*break*/, 7];
1067-
this._moveNode(i, best);
1068-
i = best;
1069-
_c.label = 6;
1070-
case 6:
1064+
else
1065+
return [3 /*break*/, 5];
10711066
return [3 /*break*/, 1];
1072-
case 7: return [2 /*return*/];
1067+
case 5:
1068+
if (i !== originalIndex) {
1069+
this.heapArray[i] = value;
1070+
}
1071+
return [2 /*return*/];
10731072
}
10741073
});
10751074
});
@@ -1080,22 +1079,30 @@ var HeapAsync = /** @class */ (function () {
10801079
*/
10811080
HeapAsync.prototype._sortNodeUp = function (i) {
10821081
return __awaiter(this, void 0, void 0, function () {
1083-
var pi;
1082+
var value, originalIndex, pi;
10841083
return __generator$1(this, function (_a) {
10851084
switch (_a.label) {
10861085
case 0:
1087-
if (!(i > 0)) return [3 /*break*/, 2];
1088-
pi = HeapAsync.getParentIndexOf(i);
1089-
return [4 /*yield*/, this.compare(this.heapArray[i], this.heapArray[pi])];
1086+
value = this.heapArray[i];
1087+
originalIndex = i;
1088+
_a.label = 1;
10901089
case 1:
1090+
if (!(i > 0)) return [3 /*break*/, 3];
1091+
pi = HeapAsync.getParentIndexOf(i);
1092+
return [4 /*yield*/, this.compare(value, this.heapArray[pi])];
1093+
case 2:
10911094
if ((_a.sent()) < 0) {
1092-
this._moveNode(i, pi);
1095+
this.heapArray[i] = this.heapArray[pi];
10931096
i = pi;
10941097
}
10951098
else
1096-
return [3 /*break*/, 2];
1097-
return [3 /*break*/, 0];
1098-
case 2: return [2 /*return*/];
1099+
return [3 /*break*/, 3];
1100+
return [3 /*break*/, 1];
1101+
case 3:
1102+
if (i !== originalIndex) {
1103+
this.heapArray[i] = value;
1104+
}
1105+
return [2 /*return*/];
10991106
}
11001107
});
11011108
});
@@ -1398,8 +1405,7 @@ var Heap = /** @class */ (function () {
13981405
if (idx <= 0) {
13991406
return -1;
14001407
}
1401-
var whichChildren = idx % 2 ? 1 : 2;
1402-
return Math.floor((idx - whichChildren) / 2);
1408+
return (idx - 1) >> 1;
14031409
};
14041410
/**
14051411
* Gets sibling index for given index.
@@ -1741,7 +1747,7 @@ var Heap = /** @class */ (function () {
17411747
if (array) {
17421748
this.heapArray = __spreadArray([], __read(array), false);
17431749
}
1744-
for (var i = Math.floor(this.heapArray.length); i >= 0; --i) {
1750+
for (var i = Heap.getParentIndexOf(this.length - 1); i >= 0; --i) {
17451751
this._sortNodeDown(i);
17461752
}
17471753
this._applyLimit();
@@ -2126,45 +2132,54 @@ var Heap = /** @class */ (function () {
21262132
* @param {Number} k Another node index
21272133
*/
21282134
Heap.prototype._moveNode = function (j, k) {
2129-
var _a;
2130-
_a = __read([this.heapArray[k], this.heapArray[j]], 2), this.heapArray[j] = _a[0], this.heapArray[k] = _a[1];
2135+
var temp = this.heapArray[j];
2136+
this.heapArray[j] = this.heapArray[k];
2137+
this.heapArray[k] = temp;
21312138
};
21322139
/**
21332140
* Move a node down the tree (to the leaves) to find a place where the heap is sorted.
21342141
* @param {Number} i Index of the node
21352142
*/
21362143
Heap.prototype._sortNodeDown = function (i) {
21372144
var length = this.heapArray.length;
2145+
var originalIndex = i;
2146+
var value = this.heapArray[i];
21382147
while (true) {
21392148
var left = 2 * i + 1;
21402149
var right = left + 1;
2141-
var best = i;
2142-
if (left < length && this.compare(this.heapArray[left], this.heapArray[best]) < 0) {
2143-
best = left;
2144-
}
2145-
if (right < length && this.compare(this.heapArray[right], this.heapArray[best]) < 0) {
2146-
best = right;
2150+
if (left >= length)
2151+
break;
2152+
var best = right >= length || this.compare(this.heapArray[left], this.heapArray[right]) < 0 ? left : right;
2153+
if (this.compare(this.heapArray[best], value) < 0) {
2154+
this.heapArray[i] = this.heapArray[best];
2155+
i = best;
21472156
}
2148-
if (best === i)
2157+
else
21492158
break;
2150-
this._moveNode(i, best);
2151-
i = best;
2159+
}
2160+
if (i !== originalIndex) {
2161+
this.heapArray[i] = value;
21522162
}
21532163
};
21542164
/**
21552165
* Move a node up the tree (to the root) to find a place where the heap is sorted.
21562166
* @param {Number} i Index of the node
21572167
*/
21582168
Heap.prototype._sortNodeUp = function (i) {
2169+
var value = this.heapArray[i];
2170+
var originalIndex = i;
21592171
while (i > 0) {
21602172
var pi = Heap.getParentIndexOf(i);
2161-
if (this.compare(this.heapArray[i], this.heapArray[pi]) < 0) {
2162-
this._moveNode(i, pi);
2173+
if (this.compare(value, this.heapArray[pi]) < 0) {
2174+
this.heapArray[i] = this.heapArray[pi];
21632175
i = pi;
21642176
}
21652177
else
21662178
break;
21672179
}
2180+
if (i !== originalIndex) {
2181+
this.heapArray[i] = value;
2182+
}
21682183
};
21692184
/**
21702185
* Return the top (highest value) N elements of the heap, without corner cases, unsorted

0 commit comments

Comments
 (0)