我需要一些帮助在JavaScript中实现Radix sort algorthim。
我在网上发现了this example,其中包含以下代码,但我不明白我是如何调用该函数的,因为它似乎是为该网站量身定制的:
// Radix sort a (base 2)
// Numbers must be in the range 0 to 2**31 - 1
function radixSort() {
readArray('i');
var b0 = new obj(); // Bin for 0 digits
var b1 = new obj(); // Bin for 1 digits
for (var i=0; i<32; ++i) {
if (form.step.checked) { // Single step
writeArray('i','a');
if (!confirm("Sort on bit "+i))
return;
}
var mask = 1<<i; // Digit (2**i)
var biggest = 2<<i; // If all of a is smaller, we're done
var zeros=0; // Number of elements in b0, b1
var ones=0;
var found=false; // Any digits past i?
for (var j=0; j<n; ++j) { // Sort into bins b0, b1
if ((a[j] & mask) == 0)
b0[zeros++] = a[j];
else
b1[ones++] = a[j];
if (a[j]>=biggest) // Any more digits to sort on?
found=true;
}
for (j=0; j<zeros; ++j) // Concatenate b0, b1 back to a
a[j]=b0[j];
for (j=0; j<ones; ++j)
a[j+zeros]=b1[j];
form.imoves.value = parseInt(form.imoves.value)+n;
if (!found)
break;
}
writeArray('i','a');
}
答案 0 :(得分:4)
术语“基数排序”是一个棘手的问题。实际上有两种不同的排序以类似的方式工作 - MSB(最高有效位)基数和LSB(最低有效位)基数。 (有时您会看到B替换为数字D)。以下是两者的实现。
MSB基数:
//arguments to sort an array:
//arr: array to be sorted
//begin: 0
//end: length of array
//bit: maximum number of bits required to represent numbers in arr
function sort(arr, begin, end, bit)
{
var i, j, mask;
i = begin;
j = end;
mask = 1 << bit;
while(i < j)
{
while(i < j && !(arr[i] & mask))
{
++i;
}
while(i < j && (arr[j - 1] & mask))
{
--j;
}
if(i < j)
{
j--;
var tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
}
}
if(bit && i > begin)
{
sort(arr, begin, i, bit - 1);
}
if(bit && i < end)
{
sort(arr, i, end, bit - 1);
}
}
sort(arr, 0, arr.length, 32); //Here I've assumed that the values in arr are integers that fit in 32 bits
LSB基数:
function insert(arr, i, j)
{
tmp = arr[i];
arr.splice(i, 1);
arr.splice(j, 0, tmp);
}
//arguments to sort an array:
//arr: array to be sorted
function sort(arr)
{
var bit, end, i, mask;
bit = 0;
while(true)
{
mask = 1 << bit;
i = 0;
end = arr.length;
while(i < end)
{
if(arr[i] & mask)
{
insert(arr, i, arr.length - 1);
end--;
}
else
{
i++;
}
}
bit++;
if(end === arr.length)
{
break;
}
}
}
我从http://visualsort.appspot.com/中删除了这些算法。然后我将它们编译为http://jashkenas.github.com/coffee-script/的javascript,并编写了插入方法/重新格式化以便于阅读。
答案 1 :(得分:1)
您提供的链接已不再可用,但我希望我的实施对您或任何感兴趣的人都尽可能清晰。
我正在实施CRLS第3版第8.2节中引入的基数排序版本
让我们从伪代码开始:
/**
* @param k: the max of input, used to create a range for our buckets
* @param exp: 1, 10, 100, 1000, ... used to calculate the nth digit
*/
Array.prototype.countingSort = function (k, exp) {
/* eslint consistent-this:0 */
/* self of course refers to this array */
const self = this;
/**
* let's say the this[i] = 123, if exp is 100 returns 1, if exp 10 returns 2, if exp is 1 returns 3
* @param i
* @returns {*}
*/
function index(i) {
if (exp)
return Math.floor(self[i] / exp) % 10;
return i;
}
const LENGTH = this.length;
/* create an array of zeroes */
let C = Array.apply(null, new Array(k)).map(() => 0);
let B = [];
for (let i = 0; i < LENGTH; i++)
C[index(i)]++;
for (let i = 1; i < k; i++)
C[i] += C[i - 1];
for (let i = LENGTH - 1; i >= 0; i--) {
B[--C[index(i)]] = this[i];
}
B.forEach((e, i) => {
self[i] = e
});
}
这是唯一棘手的部分,其余部分非常简单
Array.prototype.radixSort = function () {
const MAX = Math.max.apply(null, this);
/* let's say the max is 1926, we should only use exponents 1, 10, 100, 1000 */
for (let exp = 1; MAX / exp > 1; exp *= 10) {
this.countingSort(10, exp);
}
}
现在,您可以在此处测试此方法
let a = [589, 111, 777, 65, 124, 852, 345, 888, 553, 654, 549, 448, 222, 165];
a.radixSort()
console.log(a);
最后,如书中所提到的,这种特殊算法的工作原理只是因为count-sort是一种就地排序算法,这意味着如果两个元素相关联,它们在输入数组中的出现顺序就会被保留。
答案 2 :(得分:0)
我的版本更详细,但对于大型数据集执行速度非常快:
var testArray = [ 331, 454, 230, 34, 343, 45, 59, 453, 345, 231, 9 ];
function radixBucketSort (arr) {
var idx1, idx2, idx3, len1, len2, radix, radixKey;
var radices = {}, buckets = {}, num, curr;
var currLen, radixStr, currBucket;
len1 = arr.length;
len2 = 10; // radix sort uses ten buckets
// find the relevant radices to process for efficiency
for (idx1 = 0;idx1 < len1;idx1++) {
radices[arr[idx1].toString().length] = 0;
}
// loop for each radix. For each radix we put all the items
// in buckets, and then pull them out of the buckets.
for (radix in radices) {
// put each array item in a bucket based on its radix value
len1 = arr.length;
for (idx1 = 0;idx1 < len1;idx1++) {
curr = arr[idx1];
// item length is used to find its current radix value
currLen = curr.toString().length;
// only put the item in a radix bucket if the item
// key is as long as the radix
if (currLen >= radix) {
// radix starts from beginning of key, so need to
// adjust to get redix values from start of stringified key
radixKey = curr.toString()[currLen - radix];
// create the bucket if it does not already exist
if (!buckets.hasOwnProperty(radixKey)) {
buckets[radixKey] = [];
}
// put the array value in the bucket
buckets[radixKey].push(curr);
} else {
if (!buckets.hasOwnProperty('0')) {
buckets['0'] = [];
}
buckets['0'].push(curr);
}
}
// for current radix, items are in buckets, now put them
// back in the array based on their buckets
// this index moves us through the array as we insert items
idx1 = 0;
// go through all the buckets
for (idx2 = 0;idx2 < len2;idx2++) {
// only process buckets with items
if (buckets[idx2] != null) {
currBucket = buckets[idx2];
// insert all bucket items into array
len1 = currBucket.length;
for (idx3 = 0;idx3 < len1;idx3++) {
arr[idx1++] = currBucket[idx3];
}
}
}
buckets = {};
}
}
radixBucketSort(testArray);
console.dir(testArray);