-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathRadixSort.js
195 lines (169 loc) · 7.01 KB
/
RadixSort.js
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// TODO: Remove extract digit function and just inline the core code. I've seen this improve performance in C#. Not sure how agressively JavaScript inlines small functions.
// TODO: Compare performance versus TimSort for random, pre-sorted and constant, since TimSort is available in JavaScript thru npm
// (https://stackoverflow.com/questions/40721767/what-is-the-fastest-way-to-sort-a-largeish-array-of-numbers-in-javascript)
// TODO: Compare performance with the following:
// var numArray = new Uint32Array([140000, 104, 99]);
// numArray = numArray.sort();
// alert(numArray)
// TODO: Consider handling these cases as JavaScript .sort does
// array = [3, 5, -1, 1, NaN, 6, undefined, 2, null]
// array.sort((a,b) => isNaN(a) || a-b)
// [-1, null, 1, 2, 3, 5, 6, NaN, undefined]
var HpcAlgorithms = HpcAlgorithms || {};
HpcAlgorithms.Sorting = (function()
{
var internalState = "Message";
var privateMethod = function() {
// Do private stuff, or build internal.
return internalState;
};
var publicMethod = function() {
return privateMethod() + " stuff";
};
var extractDigit = function( a, bitMask, shiftRightAmount )
{
var digit = (a & bitMask) >>> shiftRightAmount; // extract the digit we are sorting based on
return digit;
}
var HistogramByteComponents = function(inArray, l, r)
{
var numberOfDigits = 4;
var numberOfBins = 256;
var count = new Array(numberOfDigits);
for (var d = 0; d < numberOfDigits; d++)
{
count[d] = new Array(numberOfBins);
for (var b = 0; b < numberOfBins; b++)
count[d][b] = 0;
}
for (var current = l; current <= r; current++) // Scan the array and count the number of times each digit value appears - i.e. size of each bin
{
var value = inArray[current];
count[0][ value & 0xff]++;
count[1][(value >> 8) & 0xff]++;
count[2][(value >> 16) & 0xff]++;
count[3][(value >> 24) & 0xff]++;
}
return count;
}
var HistogramByteComponentsAndKeyArray = function(inArray, l, r, getKey)
{
var numberOfDigits = 4;
var numberOfBins = 256;
var inKeys = new Array(inArray.length);
var count = new Array(numberOfDigits);
for (var d = 0; d < numberOfDigits; d++)
{
count[d] = new Array(numberOfBins);
for (var b = 0; b < numberOfBins; b++)
count[d][b] = 0;
}
for (var current = l; current <= r; current++) // Scan the array and count the number of times each digit value appears - i.e. size of each bin
{
var value = getKey(inArray[current]);
inKeys[current] = value;
count[0][ value & 0xff]++;
count[1][(value >> 8) & 0xff]++;
count[2][(value >> 16) & 0xff]++;
count[3][(value >> 24) & 0xff]++;
}
return {
count: count,
inKeys: inKeys
};
}
/**
* Radix Sort (Least Significant Digit - LSD) of unsigned integer array with values up to 32-bits (e.g. 0, 1, 2, ... 2_000_000_000, ...)
* This algorithm is not in-place - i.e. returns a sorted array
* @param {Array of numbers} inputArray Array of numbers, which must be unsigned integers of values within 32-bits
* @return {Array of numbers} Sorted array of numbers
*/
var RadixSortLsdUInt32 = function(inputArray)
{
if (typeof inputArray.constructor === Array && typeof inputArray[0] === "number") throw new TypeError("Input argument must be an array of unsigned integers");
var numberOfBins = 256;
var numberOfDigits = 4;
var Log2ofPowerOfTwoRadix = 8;
var outputArrayHasResult = false;
var bitMask = 255;
var shiftRightAmount = 0;
var outputArray = new Array(inputArray.length);
var count = HistogramByteComponents(inputArray, 0, inputArray.length - 1);
var startOfBin = new Array(numberOfDigits);
var d = 0;
for (d = 0; d < numberOfDigits; d++)
{
startOfBin[d] = new Array(numberOfBins);
startOfBin[d][0] = 0;
for (var b = 1; b < numberOfBins; b++ )
startOfBin[d][b] = startOfBin[d][b - 1] + count[d][b - 1];
}
d = 0;
while( bitMask != 0 ) // end processing digits when all the mask bits have been processed and shifted out, leaving no bits set in the bitMask
{
var startOfBinLoc = startOfBin[d];
for ( var current = 0; current < inputArray.length; current++ )
outputArray[ startOfBinLoc[ (inputArray[ current ] & bitMask) >>> shiftRightAmount ]++ ] = inputArray[ current ];
bitMask <<= Log2ofPowerOfTwoRadix;
shiftRightAmount += Log2ofPowerOfTwoRadix;
outputArrayHasResult = !outputArrayHasResult;
d++;
var tmp = inputArray, inputArray = outputArray, outputArray = tmp; // swap input and output arrays
}
return outputArrayHasResult ? outputArray : inputArray;;
}
/**
* Radix Sort (Least Significant Digit - LSD) of user defined type/class array based on a key that is a 32-bit unsigned integer (e.g. 0, 1, 2, ... 2_000_000_000, ...)
* This algorithm is not in-place - i.e. returns a sorted array. This algorithm is stable.
* @param {Array} inputArray user defined type/class (UDT) array with each element containing a key that is a 32-bit unsigned integer
* @param {function} getKey function to extract and return a numeric key from the user defined type/class to sort on
* @return {Array of numbers} Sorted array of a user defined type
*/
function RadixSortLsdUdtUInt32(inputArray, getKey) {
var numberOfBitsPerDigit = 8;
var numberOfBins = 1 << numberOfBitsPerDigit;
var numberOfDigits = 4;
var outputArray = new Array(inputArray.length);
var outSortedKeys = new Array(inputArray.length);
var outputArrayHasResult = false;
var bitMask = numberOfBins - 1;
var shiftRightAmount = 0;
var d = 0;
var retValue = HistogramByteComponentsAndKeyArray(inputArray, 0, inputArray.length - 1, getKey);
var count = retValue.count;
var inKeys = retValue.inKeys;
var startOfBin = new Array(numberOfDigits);
for (d = 0; d < numberOfDigits; d++)
{
startOfBin[d] = new Array(numberOfBins);
startOfBin[d][0] = 0;
for (var b = 1; b < numberOfBins; b++ )
startOfBin[d][b] = startOfBin[d][b - 1] + count[d][b - 1];
}
d = 0;
while( bitMask != 0 ) // end processing digits when all the mask bits have been processed and shifted out, leaving no bits set in the bitMask
{
var startOfBinLoc = startOfBin[d];
for (var current = 0; current < inputArray.length; current++)
{
var endOfBinIndex = (inKeys[current] & bitMask) >> shiftRightAmount;
var index = startOfBinLoc[endOfBinIndex];
outputArray[ index] = inputArray[current];
outSortedKeys[index] = inKeys[ current];
startOfBinLoc[endOfBinIndex]++;
}
bitMask <<= numberOfBitsPerDigit;
shiftRightAmount += numberOfBitsPerDigit;
outputArrayHasResult = !outputArrayHasResult;
d++;
var tmp = inputArray, inputArray = outputArray, outputArray = tmp; // swap input and output arrays
var tmpKeys = inKeys; inKeys = outSortedKeys; outSortedKeys = tmpKeys; // swap input and output key arrays
}
return outputArrayHasResult ? outputArray : inputArray;
}
return {
//someProperty: 'prop value',
RadixSortLsdUInt32: RadixSortLsdUInt32,
RadixSortLsdUdtUInt32: RadixSortLsdUdtUInt32
};
})();