Est-il plus rapide d’append à une collection, de le sortinger ou de l’append à une collection sortingée?

Si j’ai une Map comme celle-ci:

 HashMap map; 

et je veux obtenir une collection de valeurs sortingées par ordre naturel, quelle méthode est la plus rapide?

(UNE)

Créez une instance d’une collection sortingable comme ArrayList , ajoutez les valeurs, puis sortingez-la:

 List sortedCollection = new ArrayList(map.values()); Collections.sort(sortedCollection); 

(B)

Créez une instance d’une collection ordonnée comme TreeSet , puis ajoutez les valeurs:

 Set sortedCollection = new TreeSet(map.values()); 

Notez que la collection résultante n’est jamais modifiée, le sorting doit donc être effectué une seule fois.

TreeSet a une garantie de complexité log(n) pour les méthodes add()/remove()/contains() . Le sorting d’une ArrayList prend en charge n*log(n) mais add()/get() ne nécessite qu’une opération.

Donc, si vous récupérez principalement, et ne sortingez pas souvent, ArrayList est le meilleur choix. Si vous sortingez souvent, mais ne récupérez pas autant TreeSet serait un meilleur choix.

Théoriquement, le sorting à la fin devrait être plus rapide. Le maintien de l’état sortingé au cours du processus peut impliquer un temps CPU supplémentaire.

Du sharepoint vue du CS, les deux opérations sont NlogN, mais 1 sorting devrait avoir une constante inférieure.

Pourquoi ne pas utiliser le meilleur des deux mondes? Si vous ne l’utilisez plus jamais, sortingez en utilisant un TreeSet et initialisez une ArrayList avec le contenu

 List sortedCollection = new ArrayList( new TreeSet(map.values())); 

MODIFIER:

J’ai créé un benchmark (vous pouvez y accéder à pastebin.com/5pyPMJav ) pour tester les trois approches (ArrayList + Collections.sort, TreeSet et mon approche des deux mondes) et la mienne gagne toujours. Le fichier de test crée une carte avec 10000 éléments, dont les valeurs ont un comparateur intentionnellement horrible, puis chacune des trois stratégies a une chance de a) sortinger les données et b) les itérer. Voici un exemple de sortie (vous pouvez le tester vous-même):

EDIT: J’ai ajouté un aspect qui enregistre les appels à Thingy.compareTo (Thingy) et j’ai également ajouté une nouvelle stratégie basée sur PriorityQueues qui est beaucoup plus rapide que l’une des solutions précédentes (du moins dans le sorting).

 compareTo() calls:123490 Transformer ArrayListTransformer Creation: 255885873 ns (0.255885873 seconds) Iteration: 2582591 ns (0.002582591 seconds) Item count: 10000 compareTo() calls:121665 Transformer TreeSetTransformer Creation: 199893004 ns (0.199893004 seconds) Iteration: 4848242 ns (0.004848242 seconds) Item count: 10000 compareTo() calls:121665 Transformer BestOfBothWorldsTransformer Creation: 216952504 ns (0.216952504 seconds) Iteration: 1604604 ns (0.001604604 seconds) Item count: 10000 compareTo() calls:18819 Transformer PriorityQueueTransformer Creation: 35119198 ns (0.035119198 seconds) Iteration: 2803639 ns (0.002803639 seconds) Item count: 10000 

Étrangement, mon approche est la plus performante dans l’itération (j’aurais pensé qu’il n’y aurait pas de différence avec l’approche ArrayList en itération, est-ce que j’ai un bogue dans mon benchmark?)

Clause de non-responsabilité: Je sais que c’est probablement un sharepoint référence terrible, mais cela aide à faire passer le message et je ne l’ai certainement pas manipulé pour que mon approche gagne.

(Le code a une dépendance à apache commons / lang pour les générateurs égal / hashcode / compareTo, mais il devrait être facile de le réorganiser)

Assurez-vous de lire mon commentaire sur TreeSet en bas si vous choisissez d’implémenter B)

Si votre application ne fait que des sortings occasionnels mais itère beaucoup, je dirais que vous êtes mieux en utilisant une liste non sortingée. Triez-le une fois et profitez ensuite d’une itération plus rapide. L’itération est particulièrement rapide sur une liste de tableaux.

Toutefois, si vous souhaitez que l’ordre de sorting soit garanti tout le temps ou que vous ajoutiez / supprimiez des éléments fréquemment, utilisez une collection sortingée et recevez l’itération.

Donc, dans votre cas, je dirais que A) est la meilleure option. La liste est sortingée une fois, ne change pas et bénéficie donc d’un tableau. L’itération devrait être très rapide, surtout si vous connaissez sa ArrayList et que vous pouvez directement utiliser ArrayList.get () au lieu d’un Iterator.

J’appendais aussi que TreeSet est par définition un Set, ce qui signifie que les objects sont uniques. Un TreeSet détermine l’égalité en utilisant compareTo sur votre comparateur / comparable. Vous pourriez facilement trouver des données manquantes si vous essayez d’append deux objects dont compareTo renvoie une valeur de 0. Par exemple, l’ajout de “C”, “A”, “B”, “A” à un TreeSet renverra “A”, “B “,” C ”

Collections.sort utilise mergeSort qui possède O (nlog n).

TreeSet a l’arbre rouge-noir sous-jacent, les opérations de base ont O (logn). Donc n éléments a aussi O (nlog n).

Les deux sont donc les mêmes gros algorithmes.

L’insertion dans un SortedSet est O (log (n)) (MAIS! Le courant n et pas le n final). L’insertion dans une liste est 1.

Le sorting dans un SortedSet est déjà inclus dans l’insertion, il est donc 0. Le sorting dans une liste est O (n * log (n)).

La complexité totale de SortedSet est donc O (n * k), k

Ainsi, SortedSet a mathématiquement les meilleures performances. Mais au final, vous avez un Set au lieu d’une List (car SortedList n’existe pas) et Set vous fournit moins de fonctionnalités que List. Donc, à mon avis, la meilleure solution pour les fonctionnalités et performances disponibles est celle proposée par Sean Pasortingck Floyd:

  • utiliser un SortedSet pour l’insertion,
  • placez le SortedSet comme paramètre pour créer une liste à renvoyer.