124 votes

Pourquoi itération sur une liste serait plus rapide que l’indexation à travers elle ?

La lecture de la documentation de Java pour l'ADT Liste il dit:

La Liste dans l'interface propose quatre méthodes de positionnement (indexée) l'accès aux éléments d'une liste. Les listes (comme Java tableaux) sont en partant de zéro. Notez que ces opérations peuvent s'exécuter en temps proportionnel à la valeur de l'indice pour certaines implémentations (la classe LinkedList, par exemple). Ainsi, l'itération sur les éléments d'une liste est généralement préférable à l'indexation par elle, si l'appelant ne connaît pas la mise en œuvre.

Qu'est-ce exactement est-ce à dire? Je ne comprends pas la conclusion qui en est tirée.

211voto

Tudor Points 39539

Dans une liste, chaque élément possède un pointeur vers l'élément suivant:

head -> item1 -> item2 -> item3 -> etc.

Pour accéder item3, vous pouvez voir clairement que vous avez besoin de marcher à partir de la tête par chaque nœud jusqu'à ce que vous atteignez item3, puisque vous ne pouvez pas sauter directement.

Donc, si je voulais imprimer la valeur de chaque élément, si j'écris ceci:

for(int i = 0; i < 4; i++) {
    System.out.println(list.get(i));
}

voilà ce qui se passe:

head -> print head
head -> item1 -> print item1
head -> item1 -> item2 -> print item2
head -> item1 -> item2 -> item3 print item3

C'est horriblement inefficace parce que chaque fois que vous êtes à l'indexation, il recommence à partir du début de la liste et passe par chaque élément. Cela signifie que votre complexité est efficacement O(N^2) seulement pour parcourir la liste!

Si, au contraire, j'ai fait ceci:

for(String s: list) {
    System.out.println(s);
}

alors voilà ce qui se passe:

head -> print head -> item1 -> print item1 -> item2 -> print item2 etc.

le tout dans une seule traversée, qui est - O(N).

Maintenant, il faut aller à l'autre de la mise en œuvre de l' List qui ArrayList, que l'on est soutenu par un simple tableau. Dans ce cas, les deux traversals sont équivalentes, car un tableau est contiguë, de sorte qu'il permet aléatoire de sauts à l'arbitraire des positions.

35voto

andersoj Points 10592

La réponse est implicite ici:

Notez que ces opérations peuvent s'exécuter en temps proportionnel à la valeur de l'indice pour certaines implémentations (la classe LinkedList, par exemple)

Une liste chaînée n'est pas inhérent à l'index; l'appelant .get(x) nécessitera la mise en œuvre de la liste pour trouver la première entrée et appelez - .next() x-1 fois (pour un temps O(n) linéaire ou en temps d'accès), où un tableau soutenu la liste peut indexer en backingarray[x] en O(1) ou à temps constant.

Si vous regardez la JavaDoc pour LinkedList, vous allez voir le commentaire

Toutes les opérations de réaliser qu'elle pourrait l'être pour une liste à double liaison. Les opérations d'index dans la liste de la traversée de la liste à partir du début ou de la fin, celle qui est la plus proche de l'index spécifié.

alors que JavaDoc pour ArrayList a le même

Redimensionnable-tableau de mise en œuvre de la Liste de l'interface. Met en œuvre toutes les option de la liste des opérations, et permet à tous les éléments, y compris la valeur null. En plus de la mise en œuvre de la Liste de l'interface, cette classe fournit des méthodes pour manipuler la taille de la matrice qui est utilisé en interne pour stocker la liste. (Cette classe est à peu près équivalent à Vecteur, sauf qu'il n'est pas synchronisé.)

L' size, isEmpty, get, set, iterator, et listIterator des opérations en temps constant. L'opération d'ajout s'exécute en temps constant amorti, qui est, l'ajout de n éléments nécessite O(n) fois. Toutes les autres opérations sont exécutées en temps linéaire (grosso modo). Le facteur constant est faible par rapport à celle de l' LinkedList mise en œuvre.

Une question connexe intitulé "Big-O Résumé pour Java Collections Cadre" a une réponse pointant vers cette ressource, "Java Collections JDK6" qui peut vous être utile.

7voto

Dhruv Gairola Points 4448

Alors que l'on a accepté la réponse est certainement correct, permettez-moi de souligner un défaut mineur. Citant Tudor :

Maintenant, il faut aller à l'autre de la mise en œuvre de la Liste de liste de tableaux, que l'on est soutenu par un simple tableau. Dans ce cas, les deux ci-dessus traversals sont équivalentes, car un tableau est contiguë, de sorte qu'il permet aléatoire de sauts à l'arbitraire des positions.

Ce n'est pas tout à fait vrai. La vérité est, que

Avec une liste de tableaux, écrite à la main compté de la boucle est d'environ 3x plus rapide

source: la Conception de la Performance, Android de Google doc

Notez que le manuscrit de la boucle se réfère à la indexé itération. Je soupçonne que c'est parce que de l'itérateur qui est utilisé avec renforcée pour boucles. Il produit un mineur de performance en peine dans une structure qui est soutenu par une ligne de tableau. Je soupçonne aussi cela pourrait être vrai pour la classe Vector.

Ma règle est, utiliser l'interface de boucle à chaque fois que possible, et si vous vous souciez vraiment de la performance, l'utilisation indexé itération uniquement pour ArrayLists ou de Vecteurs. Dans la plupart des cas, vous pouvez même ignorer ce - que le compilateur peut-être l'optimisation en arrière-plan.

J'ai simplement envie de rappeler que, dans le contexte du développement d'Android, à la fois la traversals de ArrayLists sont pas nécessairement équivalents. Juste de la nourriture pour la pensée.

7voto

alex Points 186293

Itérer sur une liste avec un décalage pour la recherche, telle que i, est analogue à Shlemiel l'algorithme du peintre.

Shlemiel obtient un emploi comme un street artiste peintre, la peinture des lignes en pointillés au milieu de la route. Le premier jour, il prend un pot de peinture sur la route et les finitions à 300 mètres de la route. "C'est assez bon!", dit son patron, "vous êtes un rapide travailleur!" et lui verse un kopeck.

Le lendemain Shlemiel obtient seulement 150 mètres fait. "Eh bien, ce n'est pas presque aussi bon comme hier, mais vous êtes encore un rapide travailleur. 150 mètres est respectable", et lui verse un kopeck.

Le lendemain Shlemiel peintures de 30 mètres de la route. "Seulement 30!" hurle son patron. "C'est inacceptable! Sur la première journée, vous avez dix fois que beaucoup de travail! Ce qui se passe?"

"Je ne peux pas l'aider," dit Shlemiel. "Chaque jour, je reçois de plus en plus loin loin de la peinture!"

Source.

Cette petite histoire peut être plus facile de comprendre ce qui se passe en interne, et pourquoi il est si inefficace.

4voto

esej Points 1949

Pour Rechercher l’élément i-ème d’un `` la mise en œuvre passe par tous les éléments jusqu'à la i-ème.

Alors

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X