web-dev-qa-db-fra.com

O (n log n) vs O(n) - différences pratiques dans la complexité temporelle

n log n > n - mais cela ressemble à une relation pseudo-linear. Si n=1 billion, Connectez-vous ~ 30;

Donc n log n Sera 30 billion, Qui est 30 X n, Ordre de n. Je me demande si cette différence de complexité temporelle entre n log n and n Est significative dans la vie réelle.

Par exemple: un quick select Lors de la recherche du kème élément dans un tableau non trié est O(n) à l'aide de l'algorithme quickselect.

Si je trie le tableau et trouve le kième élément, c’est O(n log n). Pour trier un tableau avec les éléments 1 trillion, Je serais plus lent 60 times Si je faisais quicksort et index it.

37
brain storm

L’objectif principal de la notation Big-O est de vous permettre de faire les estimations comme celles que vous avez faites dans votre message et de décider vous-même si le fait de coder pour un algorithme généralement plus perfectionné vaut la peine que vous passiez à des cycles de CPU supplémentaires. acheter avec cette amélioration du code. Selon les circonstances, vous pouvez obtenir une réponse différente, même lorsque votre ensemble de données est relativement petit:

  • Si vous utilisez un appareil mobile et que l'algorithme représente une partie importante du temps d'exécution, réduire l'utilisation de la CPU signifie prolonger la durée de vie de la batterie.
  • Si vous travaillez dans un environnement concurrentiel du tout ou rien, tel qu'un système de trading haute fréquence, une micro-optimisation peut faire la différence entre gagner de l'argent et perdre de l'argent.
  • Lorsque votre profilage indique que l'algorithme en question domine le temps d'exécution dans un environnement de serveur, le passage à un algorithme plus rapide peut améliorer les performances de tous vos clients.

Une autre chose que la notation Big-O cache est le facteur de multiplication constant. Par exemple, Quick Select a un multiplicateur très raisonnable, ce qui permet de gagner du temps en l'utilisant sur des ensembles de données extrêmement volumineux.

Une autre chose que vous devez garder à l'esprit est la complexité de l'espace. Très souvent, les algorithmes avec la complexité temporelle O(N*Log N) auraient une complexité spatiale O(Log N). Cela peut poser un problème pour des ensembles de données extrêmement volumineux, par exemple lorsqu'une fonction récursive s'exécute sur un système avec une capacité de pile limitée.

55
dasblinkenlight

Ça dépend.

Je travaillais chez Amazon, il y avait une méthode qui faisait de la recherche linéaire sur une liste. Nous pourrions utiliser une table de hachage et faire la recherche dans O(1) par rapport à O (n).

J'ai suggéré le changement et il n'a pas été approuvé. parce que l'entrée était petite, cela ne ferait pas une énorme différence.

Cependant, si l'entrée est importante, cela ferait une différence.

Dans une autre société, où les données/entrées étaient énormes, utiliser un arbre, par rapport à List, a fait une énorme différence. Cela dépend donc des données et de l'architecture de l'application.

Il est toujours bon de connaître vos options et comment vous pouvez les optimiser.

29
DarthVader

Il y a des moments où vous travaillerez avec des milliards d'éléments (et plus), où la différence sera certainement importante.

Il y a d'autres moments où vous travaillerez avec moins d'un millier d'éléments, auquel cas la différence ne sera probablement pas si significative.

Si vous avez une bonne idée de ce à quoi ressembleront vos données, vous devriez avoir une bonne idée de celle à choisir dès le départ, mais la différence entre O(n) et O (n log n ) est suffisamment petit pour qu'il soit probablement préférable de commencer par celui qui est le plus simple, comparez-le et essayez de l'améliorer uniquement si vous constatez qu'il est trop lent.

Cependant, notez que O(n) peut en réalité être plus lent que O (n log n) pour toute valeur donnée de n (en particulier, mais pas nécessairement, pour les petites valeurs de n) en raison de la facteurs constants impliqués, puisque big-O les ignore (il ne prend en compte que ce qui se passe lorsque n tend vers l'infini), donc, si vous regardez uniquement à la complexité temporelle, ce que vous pensez être une amélioration peut en réalité ralentir les choses.

11
Dukeling

Dark Vador est correct. Cela dépend toujours. Il est également important de rappeler que les complexités sont asymptotiques, dans le pire des cas (généralement) et que les constantes sont abandonnées. Chacun de ceux-ci est important à considérer.

Donc, vous pouvez avoir deux algorithmes, l’un est O(n)) et l’autre est O (nlogn), et pour chaque valeur jusqu’au nombre d’atomes dans l’univers et au-delà ( à une valeur finie de n, l’algorithme O(nlogn) surpasse celui de O(n)). Cela pourrait être dû au fait que les termes d'ordre inférieur sont dominants, ou cela pourrait être dû au fait que dans la moyenne, l'algorithme O(nlogn) est en fait O (n), ou que le nombre réel d'étapes est quelque chose comme 5000 000n vs 3nlogn.

3
gms7777

PriorityQueue Trie chaque élément que vous ajoutez à chaque fois lorsque vous utilisez Collections.sort () pour trier tous les éléments en une seule fois. Mais si vous souhaitez obtenir le plus gros élément le plus rapidement possible, utilisez PriorityQueue, en revanche, si vous devez effectuer des calculs mais que l'élément doit être trié, utilisez ArrayList avec Collections.Sort est préférable.

0
Amit_Hora