2010-09-28 15 views
3

Je suis venu avec le suivant, mais cela ne fonctionne pas de manière prévisible.Radix Trier en JavaScript

var t = new Array(a.length); 
var r = 4; 
var b = 64; 

var count = new Array(1<<r); 
var pref = new Array(1<<r); 

var groups = Math.ceil(b/r); 

var mask = (1 << r) - 1; 

var shift = 0; 
for(var c = 0; c < groups; c++) 
{ 
    shift += r; 

    for(var j = 0; j < count.length; j++) 
    { 
     count[j] = 0; 
    } 

    for(var i = 0; i < a.length; i++) 
    { 
     count[ (a[i] >> shift) & mask ]++; 
    } 

    pref[0] = 0; 

    for(var i = 0; i < count.length; i++) 
    { 
     pref[i] = pref[i-1] + count[i-1]; 
    } 

    for(var i = 0; i < a.length; i++) 
    { 
     t[ pref[ (a[i] >> shift) & mask ]++ ] = a[i]; 
    } 

    for(var i = 0; i < a.length; i++) 
    { 
     a[i] = t[i]; 
    } 
    // a is sorted? 
} 
+0

Pourquoi ne mettez-vous pas à zéro les fonctions 'count',' pref' et 'groups'? Les tableaux dans JS, même lorsqu'ils sont créés via 'new Array (length)' commencent avec un contenu indéfini, et 'undefined + 0' est' NaN'. –

+0

@Mike: D'abord, je ne suis même pas tout à fait sûr comment ce genre est supposé fonctionner, donc je ne suis pas sûr de ce qui est cassé. 'count' est déjà mis à zéro,' pref' est initialisé avant d'être utilisé, et 'groups' n'est pas un tableau. –

+0

Un tri de * radix * trie en regardant des pièces de la clé de tri, des pièces suffisamment petites pour que toutes les valeurs possibles d'une pièce puissent décrire un nombre gérable de listes discrètes. Imaginez trier votre collection de CD: faites d'abord des piles par la deuxième lettre du nom de l'artiste, puis passez les piles A - Z et faites de nouvelles piles par première lettre. Lorsque vous reprenez les piles A et Z et que vous les alignez de gauche à droite sur une étagère, elles sont triées! – Pointy

Répondre

5

Cette boucle fait essentiellement la même chose, d'une façon plus Javascript-y:

for (var div = 1, radix = 16; div < 65536 * 65536; div *= radix) { 
    var piles = []; 

    for (var i = 0; i < a.length; ++i) { 
    var p = Math.floor(a[i]/div) % radix; 
    (piles[p] || (piles[p] = [])).push(a[i]); 
    } 

    for (var i = 0, ai = 0; i < piles.length; ++i) { 
    if (!piles[i]) continue; 
    for (var pi = 0; pi < piles[i].length; ++pi) 
     a[ai++] = piles[i][pi]; 
    } 
} 

au lieu de le faire comme un programmeur C pourrait, cette boucle construit une liste de listes, une liste pour chaque possible Valeur 4 bits J'évite les opérateurs de décalage de bits parce que c'est Javascript et alors qu'ils font travaillent, les choses deviennent drôles quand les nombres deviennent grands. En commençant par les 4 bits les plus faibles de chaque valeur de "a", le code copie cet élément de "a" à la fin de l'une des "piles", c'est-à-dire celle correspondant à la valeur de 4 bits. Il rassemble ensuite les piles et reconstruit "a" à partir de toutes les valeurs dont les 4 bits bas étaient 0, puis 1, etc. (Clairement, il y aura des trous, donc ceux-ci sont ignorés.) A la fin de chaque itération de la boucle globale, le diviseur est multiplié par la base, de sorte que l'ensemble suivant de 4 bits sera examiné.

Une fois que le diviseur a épuisé la plage disponible d'entiers, c'est fait.

Notez que cela fonctionnera uniquement pour positifs nombres. Faire cela avec des nombres négatifs devient un peu bizarre; il pourrait être plus facile de supprimer les nombres négatifs dans un tableau séparé, de retourner le signe, de trier, puis de retourner. Trier les nombres positifs, puis enfin coller les nombres négatifs inversés (retournant les signes) à l'avant des nombres positifs triés. `A` contient le tableau d'entrée des entiers?

+0

Cela fonctionne, et je vais le démonter pour voir si je peux envelopper ma tête autour d'elle. Je voudrais implémenter ce genre dans une partie de mon code, est-ce que j'ai votre permission pour le faire? –

+0

Bien sûr; C'est un truc assez commun.J'ai aimé votre question parce que j'essayais d'intéresser un de mes enfants à la perspective de trier ma vieille collection LP :-) – Pointy

0

cette

for(var i = 0; i < count.length; i++) 
{ 
    pref[i] = pref[i-1] + count[i-1]; 
} 

est un problème parce que la première itération, i est égal à zéro et ainsi pref[ 0 - 1 ] ne va pas fonctionner très bien.

Je n'ai pas de référence pour les tris radix pratiques pour déterminer ce que vous devriez faire ici.

+0

Le tableau "pref" est destiné à contenir le nombre de valeurs pour chaque compartiment radix. Si je le faisais en Javascript, je ne le ferais pas du tout; c'est comme un programme C transcrit. – Pointy

+0

@Pointy: J'ai obtenu le code presque textuellement d'une implémentation C#. Pourrait être pourquoi il semble que c'est transcrit. ;) –