web-dev-qa-db-fra.com

Comment la complexité du Seau Sort est-elle O (N + K) si nous appliquons des godets à l'aide de listes liées?

Je suis curieux de savoir pourquoi la sorte de seau a un runtime de O (N + K) si nous utilisons des godets mis en œuvre avec des listes liées. Par exemple, supposons que nous ayons cette entrée:

n = no of element= 8
k = range = 3

array = 2,2,1,1,1,3,1,3

Les godets ressembleront à ceci:

1: 1 -> 1 -> 1 -> 1
2: 2 -> 2
3: 3 -> 3

Le temps total consacré à l'insertion dans ces godets est O (N), en supposant que nous stockions un pointeur de queue dans les listes liées.

Pour supprimer, nous devons aller à chaque godet, puis supprimer chaque noeud dans ce seau. Par conséquent, la complexité devrait être O (k * la longueur moyenne de la liste de liens de godet) car nous traversons chaque liste liée.

Cependant, j'ai lu que la complexité de la sorte de godet est O (n + k). Pourquoi cela n'est-il pas d'accord avec mon analyse? S'il vous plaît corrigez-moi comme je suis toujours en train d'apprendre la complexité informatique.

23
Suri

Votre analyse est presque CORRECT, mais il y a un détail important qui vous manque.

À l'heure actuelle, vous êtes correct que itération de la matrice d'entrée pour distribuer les éléments dans des seaux prend du temps O (N). Cependant, vous êtes légèrement éteint lorsque vous dites que la quantité totale de temps requise pour assembler le tableau est O (k * (nombre moyen d'éléments par godet)). Notez que, parce qu'il y ait n éléments et kaux k, cela irait à O (K * (N/K)) = O (n), pour un temps d'exécution total de O (N). Pour voir pourquoi la réponse réelle est O (N + K), nous devons avoir l'air plus attentivement à ce terme Big-O.

Pour commencer, vous avez absolument raison que la durée moyenne que vous dépensez sur chaque godet est O (N/K). Vous dites ensuite que puisqu'il y a des godets K, le temps d'exécution total est alors O (k * (n/k)) = O (n). Cependant, cela est incorrect: en particulier, c'est non vrai que k * o (n/k) = O (n). La raison en est que le terme O (n/k) cache un facteur constant. Lorsque vous visitez chaque godet et jetez un coup d'œil aux éléments qu'il contient, il ne prend pas exactement N/K Time, voire de multiples multiples constants de N/K. Par exemple, que se passe-t-il si le godet est vide? Dans ce cas, vous dépensez toujours une certaine quantité de temps en regardant le seau, car vous devez déterminer que vous ne devriez pas itérer sur ses éléments. Ainsi, une représentation plus précise du temps requis par godet est quelque chose comme c(n/k) + c1, où c et C1 sont des constantes spécifiques à la mise en œuvre. Cette expression est, bien sûr, O (n/k).

La capture est ce qui se passe lorsque vous multipliez cette expression par K pour obtenir la quantité totale de travail effectuée. Si vous calculez

k * (c(n/k) + c1)

Vous obtenez

cn + c1k

Comme vous pouvez le constater, cette expression dépend directement de k, de sorte que le temps d'exécution total est O (n + k).

Une voie plus directe d'arriver à ce résultat serait de regarder le code de la deuxième étape du type de seau, qui ressemble à ceci:

For each bucket b:
    For each element x in b:
        Append x to the array.

Combien de travail est fait dans l'ensemble? Eh bien, il y a des godets différents différents, de sorte que la boucle la plus externe doit prendre au moins O(k) fois, car nous devons regarder dans chaque seau. À l'intérieur, la boucle interne exécutera un total de O(n) fois globalement, car il y a un total de N éléments distribués dans les compartiments. À partir de là, nous obtenons le Total du temps d'exécution O (N + K).

La raison pour laquelle il est important est que cela signifie que si vous essayez de faire un type de seau avec un grand nombre de seaux (disons, beaucoup plus grand que N), le temps d'exécution pourrait être dominé par le temps nécessaire pour rechercher tous les godets à la recherche de tous les godets à la recherche de Les godets que vous avez réellement utilisés, même si la plupart d'entre eux sont vides. La raison pour laquelle le tri radax est utile est qu'il utilise plusieurs itérations de type de godet où il n'y a que deux godets, qui fonctionne dans le temps O (n + 2) = O (n). Puisque vous n'avez besoin que d'itérations O (lg u) de ceci (où vous êtes la valeur maximale dans le tableau), le temps d'exécution est O (n lg u) au lieu de O (n + u) que vous obtiendriez du seau Trier, ce qui est bien pire.

J'espère que cela t'aides!

55
templatetypedef