Nous allons commencer avec quelques réécriture de votre code en C, car C plus familier pour moi de l'expliquer. Donc, permet de rappeler votre code avec quelques commentaires:
int
counting_sort(int a[], int a_len, int maxVal)
{
int i, j, outPos = 0;
int bucket_len = maxVal+1;
int bucket[bucket_len]; /* simple bucket structure */
memset(bucket, 0, sizeof(int) * bucket_len);
/* one loop bucket processing */
for (i = 0; i < a_len; i++)
{
bucket[a[i]]++; /* simple work with buckets */
}
for (i=0; i < bucket_len; i++)
{
for (j = 0; j < bucket[i]; j++)
{
a[outPos++] = i;
}
}
return 0;
}
Maintenant permet d'offrir à ce mec un peu réaliste de données:
[126, 348, 343, 432, 316, 171, 556, 223, 670, 201]
Sur la sortie, nous avons
[126, 171, 201, 223, 316, 343, 348, 432, 556, 670]
Il semble que tout est ok? Pas encore de. Permet de regarder maxVal. Il est de 670 (!) Pour le tri de tableau de 10 éléments, ici, nous avons utilisé la matrice de 670 éléments, principalement des zéros. Terriblement. Pour gérer ce problème de comptage, de tri, nous avons deux façons possibles de généralisation:
1) tout d'Abord, comme pour se faire de tri chiffres-sage. Ceci est appelé radix-tri. Permet de montrer un peu de code, et essayer d'en faire à proximité de comptage, de tri code que possible. Regardez à nouveau les commentaires:
int
radix_sort(int a[], int a_len, int ndigits)
{
int i;
int b[a_len];
int expn = 1;
/* additional loop for digits */
for (i = 0; i != ndigits; ++i)
{
int j;
int bucket[10] = {0}; /* still simple buckets */
/* bucket processing becomes tricky */
for (j = 0; j != a_len; ++j)
bucket[ a[j] / expn % 10 ]++;
for (j = 1; j != 10; ++j)
bucket[j] += bucket[j - 1];
for (j = a_len - 1; j >= 0; --j)
b[--bucket[a[j] / expn % 10]] = a[j];
for (j = 0; j != a_len; ++j)
a[j] = b[j];
expn *= 10;
}
}
Nous sommes en négociation multiplicateur près de N pour la mémoire. Le Profit? Peut-être. Mais dans certains cas, le multiplicateur près de N est très important. Programme de travail d'une journée et de travail d'une semaine sont très différentes de vue des utilisateurs, même si les deux œuvres 1*O(N) et 7*O(N) respectivement. Nous sommes donc en venir à une seconde généralisation:
2) Deuxièmement, comme pour se faire des seaux de plus en plus sophistiqués. Ceci est appelé le seau de tri.
Permet une fois de plus, avec un peu de code. Je préfère plus de code avant arguments philosophiques. Toujours regarder les commentaires, ils sont essentiels.
int
bucket_sort(int a[], int a_len, int maxVal)
{
int i, aidx;
typedef struct tag_list {
int elem;
struct tag_list *next;
} list_t, *list_p;
list_p bucket[10] = {0}; /* sophisticated buckets */
/* one loop simple processing with one more inner loop
to get sorted buckets (insert-sort on lists, Cormen-style) */
for (i = 0; i != a_len; ++i)
{
int bnum = (10 * a[i]) / maxVal;
list_p bptr = bucket[bnum];
list_p belem = malloc(sizeof(list_t));
belem->elem = a[i];
if (bptr == 0)
{
bucket[bnum] = belem;
belem->next = 0;
continue;
}
else if (a[i] <= bptr->elem)
{
belem->next = bptr;
bucket[bnum] = belem;
continue;
}
else
{
while (bptr != 0)
{
if ((bptr->elem <= a[i]) && ((bptr->next == 0) || (bptr->next->elem > a[i])))
{
belem->next = bptr->next;
bptr->next = belem;
break;
}
}
}
}
/* one loop (looks as two) to get all back */
aidx = 0;
for (i = 0; i != 10; ++i)
{
list_p bptr = bucket[i];
while (bptr)
{
list_p optr = bptr;
a[aidx] = bptr->elem;
aidx += 1;
bptr = bptr->next;
free(optr);
}
}
return 0;
}
Alors, que faisons-nous ici? Nous sommes en négociation sophistiqués seau de la structure et de l'exigence de la mémoire allouée dynamiquement, mais la victoire de mémoire statique, et le multiplicateur près de N dans la moyenne.
Maintenant, permet de rappeler ce que nous avons vu dans le code:
- Comptage tri -- simples seaux, un traitement simple, surcharge de la mémoire
- Radix genre -- de simples seaux, de traitement sophistiqués, la vitesse, les frais généraux (et encore besoin de plus de mémoire statique)
- Seau tri -- sophistiqué seaux, un traitement simple, nécessite de la mémoire dynamique, bonne moyenne
Radix et un seau sortes sont donc de deux généralisations de comptage, de tri. Ils ont beaucoup en commun avec le comptage de tri et les uns avec les autres, mais dans tous les cas nous sont en train de perdre quelque chose et de gagner quelque chose. Génie logiciel est un équilibre entre ces possibilités.