Que signifie exactement O (log n)?

2140

J'apprends les temps de fonctionnement et les temps amortis de Big O Notation. Je comprends la notion de temps linéaire O (n) , ce qui signifie que la taille de l'entrée affecte la croissance de l'algorithme proportionnellement ... et il en va de même pour, par exemple, le temps quadratique O (n 2 ), etc. , comme les générateurs de permutation, avec O (n!) fois, qui croissent par factorielles.

Par exemple, la fonction suivante est O (n) car l'algorithme croît proportionnellement à son entrée n :

f(int n) {
  int i;
  for (i = 0; i < n; ++i)
    printf("%d", i);
}

De même, s'il y avait une boucle imbriquée, le temps serait O (n 2 ).

Mais qu'est-ce que O (log n) exactement ? Par exemple, que signifie dire que la hauteur d'un arbre binaire complet est O (log n) ?

Je sais (peut-être pas trop en détail) ce qu'est le logarithme, dans le sens où: log 10 100 = 2, mais je ne comprends pas comment identifier une fonction avec un temps logarithmique.

Andreas Grech
la source
61
Un arbre binaire à 1 nœud a une hauteur log2 (1) +1 = 1, un arbre à 2 nœuds a une hauteur log2 (2) +1 = 2, un arbre à 4 nœuds a une hauteur log2 (4) +1 = 3, et bientôt. Un arbre à n nœuds a une hauteur log2 (n) +1, donc l'ajout de nœuds à l'arbre entraîne une croissance logarithmique de sa hauteur moyenne.
David R Tribble
36
Une chose que je vois dans la plupart des réponses est qu'elles décrivent essentiellement "O (quelque chose)" signifie que le temps d'exécution de l'algorithme croît proportionnellement à "quelque chose". Étant donné que vous avez demandé la «signification exacte» de «O (log n)», ce n'est pas vrai. C'est la description intuitive de la notation Big-Theta, pas Big-O. O (log n) signifie intuitivement que le temps de fonctionnement augmente au plus proportionnellement à "log n": stackoverflow.com/questions/471199/…
Mehrdad Afshari
31
Je me souviens toujours de diviser pour mieux régner comme exemple pour O (log n)
RichardOD
14
Il est important de réaliser que son log base 2 (pas base 10). En effet, à chaque étape d'un algorithme, vous supprimez la moitié de vos choix restants. En informatique, nous traitons presque toujours la base de log 2 car nous pouvons ignorer les constantes. Cependant, il y a quelques exceptions (c'est-à-dire que les temps d'exécution de Quad Tree sont la base de journal 4)
Ethan
13
@Ethan: Peu importe la base dans laquelle vous vous trouvez, car la conversion de base n'est qu'une multiplication constante, la formule est log_b (x) = log_d (x) / log_d (b). Log_d (b) sera juste une constante.
mindvirus

Réponses:

2711

Je ne comprends pas comment identifier une fonction avec une heure de journal.

Les attributs les plus courants de la fonction d'exécution logarithmique sont les suivants:

  • le choix de l'élément suivant sur lequel effectuer une action est l'une des nombreuses possibilités, et
  • un seul devra être choisi.

ou

  • les éléments sur lesquels l'action est effectuée sont des chiffres de n

C'est pourquoi, par exemple, rechercher des personnes dans un annuaire téléphonique est O (log n). Vous n'avez pas besoin de vérifier chaque personne dans l'annuaire pour trouver la bonne personne; au lieu de cela, vous pouvez simplement diviser pour mieux régner en recherchant en fonction de la position alphabétique de son nom, et dans chaque section, il vous suffit d'explorer un sous-ensemble de chaque section avant de finalement trouver le numéro de téléphone de quelqu'un.

Bien sûr, un annuaire téléphonique plus long vous prendra encore plus de temps, mais il n'augmentera pas aussi rapidement que l'augmentation proportionnelle de la taille supplémentaire.


Nous pouvons étendre l'exemple de l'annuaire téléphonique pour comparer d'autres types d'opérations et leur durée d'exécution. Nous supposerons que notre annuaire téléphonique comporte des entreprises (les "Pages jaunes") qui ont des noms uniques et des personnes (les "Pages blanches") qui peuvent ne pas avoir de noms uniques. Un numéro de téléphone est attribué à au plus une personne ou une entreprise. Nous supposerons également qu'il faut un temps constant pour passer à une page spécifique.

Voici les temps d'exécution de certaines opérations que nous pourrions effectuer sur l'annuaire téléphonique, du plus rapide au plus lent:

  • O (1) (dans le pire des cas): étant donné la page sur laquelle se trouve le nom d'une entreprise et le nom de l'entreprise, recherchez le numéro de téléphone.

  • O (1) (dans le cas moyen): Étant donné la page sur laquelle se trouve le nom d'une personne et son nom, recherchez le numéro de téléphone.

  • O (log n): Étant donné le nom d'une personne, trouvez le numéro de téléphone en choisissant un point au hasard à mi-chemin dans la partie du livre que vous n'avez pas encore recherchée, puis vérifiez si le nom de la personne est à ce point. Répétez ensuite le processus à mi-chemin de la partie du livre où se trouve le nom de la personne. (Il s'agit d'une recherche binaire du nom d'une personne.)

  • O (n): recherchez toutes les personnes dont les numéros de téléphone contiennent le chiffre "5".

  • O (n): Étant donné un numéro de téléphone, recherchez la personne ou l'entreprise avec ce numéro.

  • O (n log n): Il y a eu une confusion au bureau de l'imprimante, et notre annuaire téléphonique avait toutes ses pages insérées dans un ordre aléatoire. Corrigez l'ordre afin qu'il soit correct en regardant le prénom sur chaque page, puis en plaçant cette page à l'endroit approprié dans un nouvel annuaire téléphonique vide.

Pour les exemples ci-dessous, nous sommes maintenant au bureau de l'imprimante. Les annuaires téléphoniques attendent d'être envoyés par la poste à chaque résident ou entreprise, et il y a un autocollant sur chaque annuaire téléphonique indiquant où il doit être envoyé. Chaque personne ou entreprise reçoit un annuaire téléphonique.

  • O (n log n): Nous voulons personnaliser l'annuaire téléphonique, nous allons donc trouver le nom de chaque personne ou entreprise dans leur copie désignée, puis encercler leur nom dans le livre et écrire une courte note de remerciement pour leur patronage .

  • O (n 2 ): Une erreur s'est produite au bureau et chaque entrée dans chacun des annuaires téléphoniques a un "0" supplémentaire à la fin du numéro de téléphone. Prenez un peu de blanc et retirez chaque zéro.

  • O (n · n!): Nous sommes prêts à charger les répertoires téléphoniques sur le quai d'expédition. Malheureusement, le robot qui était censé charger les livres est devenu détraqué: il place les livres dans le camion dans un ordre aléatoire! Pire encore, il charge tous les livres dans le camion, puis vérifie s'ils sont dans le bon ordre, et sinon, il les décharge et recommence. (C'est le genre de bogo redouté .)

  • O (n n ): vous réparez le robot pour qu'il charge correctement les objets. Le lendemain, l'un de vos collègues vous fait une farce et connecte le robot du quai de chargement aux systèmes d'impression automatisés. Chaque fois que le robot va charger un livre original, l'imprimante d'usine fait une copie de tous les répertoires! Heureusement, les systèmes de détection de bogues du robot sont suffisamment sophistiqués pour que le robot n'essaie pas d'imprimer encore plus de copies lorsqu'il rencontre un livre en double pour le chargement, mais il doit toujours charger chaque livre original et en double qui a été imprimé.

John Feminella
la source
81
@cletus: Coïncident, j'ai peur. Je l'ai choisi parce que les annuaires téléphoniques ont un grand N, les gens comprennent ce qu'ils sont et ce qu'ils font, et parce qu'il est polyvalent à titre d'exemple. De plus, je dois utiliser des robots dans mon explication! Une victoire tous azimuts. (De plus, il semble que votre réponse ait été faite avant même que je ne soit membre de StackOverflow pour commencer!)
John Feminella
12
"Une erreur s'est produite au bureau, et chaque entrée dans chacun des annuaires téléphoniques a un" 0 "supplémentaire à la fin du numéro de téléphone. Prenez du blanc et supprimez chaque zéro." <- ce n'est pas un ordre N au carré. N est défini comme la taille de l'entrée. La taille de l'entrée est le nombre de numéros de téléphone, qui est le nombre de numéros par livre multiplié par le nombre de livres. C'est toujours une opération de temps linéaire.
Billy ONeal
21
@Billy: Dans cet exemple, Nest le nombre de personnes dans un seul livre. Parce que chaque personne dans l'annuaire reçoit également sa propre copie de l'annuaire, il existe des annuaires N identiques , chacun avec des Npersonnes, qui est O (N ^ 2).
John Feminella
48
N'est-ce pas O (1) le meilleur cas, plutôt que le pire comme il est étrangement mis en évidence?
Svip
54
Il m'a fallu du temps O (long⅝n! N-55/2) pour trouver une définition O (log n) qui a finalement du sens. +1
iAteABug_And_iLiked_it
611

O(log N)signifie essentiellement que le temps augmente linéairement tandis que le naugmente de façon exponentielle. Donc, s'il faut deux 1secondes pour calculer les 10éléments, il faudra des 2secondes pour calculer les 100éléments, des 3secondes pour calculer les 1000éléments, etc.

C'est O(log n)lorsque nous divisons et conquérons des types d'algorithmes, par exemple la recherche binaire. Un autre exemple est le tri rapide où chaque fois que nous divisons le tableau en deux parties et chaque fois qu'il faut du O(N)temps pour trouver un élément pivot. D'où N O(log N)

fastcodejava
la source
109
Trois lignes de sagesse qui l'emportent sur toutes les autres réponses aux dissertations ... :) Juste au cas où quelqu'un le manquerait, dans le contexte de programmation, la base du journal est 2 (pas 10), donc O (log n) s'échelonne comme 1 sec pendant 10 éléments, 2 sec pour 20, 3 pour 40 etc.
nawfal
3
D'accord, concis et clair, bien que la question finale du PO soit de savoir comment identifier une fonction logarithmique, pas tout à fait "qu'est-ce que c'est"
Adam
4
oui, la fonction logarithmique est inverse de la fonction exponentielle. ((log x) base a) est inverse de (a power x). Une analyse qualitative de ces fonctions avec des graphiques donnerait plus d'intuition.
suréchange
7
Cela m'a pris environ 3 lectures pour réaliser que ce n'était pas mal. Le temps monte linéairement, tandis que le nombre d'éléments est exponentiel. Cela signifie plus d'éléments en moins de temps . C'est mentalement éprouvant pour ceux qui visualisent logcomme la courbe logarithmique familière sur un graphique.
Qix - MONICA A ÉTÉ BRUÉE le
1
Je pense que c'est une très bonne réponse, sauf pour la partie où il prétend que la recherche binaire est un algorithme de division et de conquête. Ça ne l'est pas.
code_dredd
579

Beaucoup de bonnes réponses ont déjà été postées à cette question, mais je pense qu'il nous manque vraiment une réponse importante - à savoir la réponse illustrée.

Que signifie dire que la hauteur d'un arbre binaire complet est O (log n)?

Le dessin suivant représente un arbre binaire. Remarquez comment chaque niveau contient le double du nombre de nœuds par rapport au niveau supérieur (d'où binaire ):

Arbre binaire

La recherche binaire est un exemple de complexité O(log n). Disons que les nœuds au niveau inférieur de l'arborescence de la figure 1 représentent des éléments dans une collection triée. La recherche binaire est un algorithme de division et de conquête, et le dessin montre comment nous aurons besoin (au plus) de 4 comparaisons pour trouver l'enregistrement que nous recherchons dans cet ensemble de données de 16 éléments.

Supposons que nous avions à la place un ensemble de données avec 32 éléments. Continuez le dessin ci-dessus pour trouver que nous aurons maintenant besoin de 5 comparaisons pour trouver ce que nous recherchons, car l'arbre n'a augmenté que d'un niveau plus profond lorsque nous avons multiplié la quantité de données. En conséquence, la complexité de l'algorithme peut être décrite comme un ordre logarithmique.

Le traçage log(n)sur une feuille de papier ordinaire se traduira par un graphique où la montée de la courbe ralentit à nmesure que les augmentations:

O (log n)

Jørn Schou-Rode
la source
60
"Remarquez comment chaque niveau contient le double nombre de nœuds par rapport au niveau supérieur (donc binaire)" C'est incorrect. Ce que vous décrivez est un arbre binaire équilibré . Un arbre binaire signifie simplement que chaque nœud a au plus deux enfants.
Oenotria
8
En fait, c'est un arbre binaire équilibré très spécial, appelé arbre binaire complet. J'ai modifié la réponse mais j'ai besoin de quelqu'un pour l'approuver.
user21820
5
Un arbre binaire complet n'a pas besoin d'avoir le dernier niveau pour être complètement rempli. Je dirais qu'un «arbre binaire complet» est plus approprié.
M. AJ
Votre réponse essaie de répondre plus concrètement au problème d'origine de l'OP, donc c'est mieux que la réponse actuellement acceptée (IMO), mais elle est encore très incomplète: vous donnez juste un demi-exemple et 2 images ...
nbro
2
Cet arbre contient 31 éléments, pas 16. Pourquoi est-il appelé un ensemble de données de 16 éléments? Chaque nœud sur celui-ci représente un nombre, sinon ce serait un arbre binaire inefficace: P
Perry Monschau
245

L'explication ci-dessous utilise le cas d'un arbre binaire entièrement équilibré pour vous aider à comprendre comment nous obtenons la complexité temporelle logarithmique.

L'arbre binaire est un cas où un problème de taille n est divisé en sous-problème de taille n / 2 jusqu'à atteindre un problème de taille 1:

hauteur d'un arbre binaire

Et c'est ainsi que vous obtenez O (log n) qui est la quantité de travail qui doit être effectuée sur l'arborescence ci-dessus pour trouver une solution.

Un algorithme commun avec une complexité temporelle O (log n) est la recherche binaire dont la relation récursive est T (n / 2) + O (1), c'est-à-dire qu'à chaque niveau suivant de l'arbre, vous divisez le problème en deux et effectuez une quantité de travail supplémentaire constante.

2cupsOfTech
la source
2
débutant ici. Pourriez-vous donc dire que la hauteur de l'arbre est le taux de division par récursivité pour atteindre la taille n = 1?
Cody
@Cody, oui pour la plupart, votre observation est exacte. Cet exemple illustre / utilise log_2. Votre observation irait au log_2- delà et serait exacte pour n'importe log_xx > 1. Cependant, faire une division droite peut ne pas conduire à 1 exactement, vous pouvez donc dire la division récursive jusqu'à ce que Ceiling()la dernière division soit égale à 1, ou quelque chose de similaire.
James Oravec
199

Aperçu

D'autres ont donné de bons exemples de diagrammes, tels que les diagrammes d'arbre. Je n'ai vu aucun exemple de code simple. Donc, en plus de mon explication, je fournirai quelques algorithmes avec des instructions d'impression simples pour illustrer la complexité des différentes catégories d'algorithmes.

Tout d'abord, vous voudrez avoir une idée générale du logarithme, que vous pouvez obtenir sur https://en.wikipedia.org/wiki/Logarithm . Utilisation des sciences naturelles eet logarithme naturel. Les disciples du génie utiliseront log_10 (base de journal 10) et les informaticiens utiliseront beaucoup log_2 (base de journal 2), car les ordinateurs sont basés sur le binaire. Parfois, vous verrez des abréviations de log naturel comme ln(), les ingénieurs laissent normalement le _10 éteint et utilisent simplement log()et log_2 est abrégé en lg(). Tous les types de logarithmes se développent de manière similaire, c'est pourquoi ils partagent la même catégorie de log(n).

Lorsque vous regardez les exemples de code ci-dessous, je recommande de regarder O (1), puis O (n), puis O (n ^ 2). Une fois que vous êtes bon avec ceux-ci, regardez les autres. J'ai inclus des exemples clairs ainsi que des variations pour montrer comment des changements subtils peuvent toujours entraîner la même catégorisation.

Vous pouvez considérer O (1), O (n), O (logn), etc. comme des classes ou des catégories de croissance. Certaines catégories prendront plus de temps que d'autres. Ces catégories nous permettent de classer les performances de l'algorithme. Certains se sont développés plus rapidement à mesure que l'entrée n augmente. Le tableau suivant montre numériquement cette croissance. Dans le tableau ci-dessous, considérez log (n) comme le plafond de log_2.

entrez la description de l'image ici

Exemples de codes simples de diverses catégories Big O:

O (1) - Exemples à temps constant:

  • Algorithme 1:

L'algorithme 1 s'imprime bonjour une fois et ne dépend pas de n, il s'exécutera donc toujours en temps constant O(1).

print "hello";
  • Algorithme 2:

L'algorithme 2 s'imprime bonjour 3 fois, mais il ne dépend pas d'une taille d'entrée. Même à mesure que n grandit, cet algorithme n'imprimera toujours bonjour que 3 fois. Cela étant dit 3, est une constante, donc cet algorithme l'est aussi O(1).

print "hello";
print "hello";
print "hello";

O (log (n)) - Exemples logarithmiques:

  • Algorithme 3 - Cela agit comme "log_2"

L'algorithme 3 illustre un algorithme qui s'exécute dans log_2 (n). Remarquez la post-opération de la boucle for multiple la valeur actuelle de i par 2, donc iva de 1 à 2 à 4 à 8 à 16 à 32 ...

for(int i = 1; i <= n; i = i * 2)
  print "hello";
  • Algorithme 4 - Cela agit comme "log_3"

L'algorithme 4 illustre log_3. L'avis iva de 1 à 3 à 9 à 27 ...

for(int i = 1; i <= n; i = i * 3)
  print "hello";
  • Algorithme 5 - Cela agit comme "log_1.02"

L'algorithme 5 est important, car il permet de montrer que tant que le nombre est supérieur à 1 et que le résultat est multiplié à plusieurs reprises contre lui-même, vous regardez un algorithme logarithmique.

for(double i = 1; i < n; i = i * 1.02)
  print "hello";

O (n) - Exemples de temps linéaire:

  • Algorithme 6

Cet algorithme est simple, qui s'imprime bonjour n fois.

for(int i = 0; i < n; i++)
  print "hello";
  • Algorithme 7

Cet algorithme montre une variation, où il s'imprimera bonjour n / 2 fois. n / 2 = 1/2 * n. Nous ignorons la constante 1/2 et voyons que cet algorithme est O (n).

for(int i = 0; i < n; i = i + 2)
  print "hello";

O (n * log (n)) - nlog (n) Exemples:

  • Algorithme 8

Considérez cela comme une combinaison de O(log(n))et O(n). L'imbrication des boucles for nous aide à obtenir leO(n*log(n))

for(int i = 0; i < n; i++)
  for(int j = 1; j < n; j = j * 2)
    print "hello";
  • Algorithme 9

L'algorithme 9 est comme l'algorithme 8, mais chacune des boucles a permis des variations, ce qui a pour résultat que le résultat final est O(n*log(n))

for(int i = 0; i < n; i = i + 2)
  for(int j = 1; j < n; j = j * 3)
    print "hello";

O (n ^ 2) - n au carré Exemples:

  • Algorithme 10

O(n^2) s'obtient facilement en imbriquant un standard pour les boucles.

for(int i = 0; i < n; i++)
  for(int j = 0; j < n; j++)
    print "hello";
  • Algorithme 11

Comme l'algorithme 10, mais avec quelques variantes.

for(int i = 0; i < n; i++)
  for(int j = 0; j < n; j = j + 2)
    print "hello";

O (n ^ 3) - n cubes Exemples:

  • Algorithme 12

C'est comme l'algorithme 10, mais avec 3 boucles au lieu de 2.

for(int i = 0; i < n; i++)
  for(int j = 0; j < n; j++)
    for(int k = 0; k < n; k++)
      print "hello";
  • Algorithme 13

Comme l'algorithme 12, mais avec quelques variations qui donnent toujours O(n^3).

for(int i = 0; i < n; i++)
  for(int j = 0; j < n + 5; j = j + 2)
    for(int k = 0; k < n; k = k + 3)
      print "hello";

Sommaire

Ce qui précède donne plusieurs exemples simples et des variations pour aider à démontrer quels changements subtils peuvent être introduits qui ne changent vraiment pas l'analyse. J'espère que cela vous donnera suffisamment d'informations.

James Oravec
la source
17
Impressionnant. La meilleure explication que j'ai jamais vue pour moi. Ce serait mieux si O(n^2)est noté comme une combinaison de O(n)et O(n), donc O(n) * O(n) = O(n * n) = O(n^2). On a l'impression de sauter un peu sans cette équation. C'est la répétition d'une explication préalable, mais je pense que cette répétition peut donner plus de confiance aux lecteurs pour la compréhension.
Eonil
2
C'est tout simplement la meilleure explication de tous les temps.
Edgar Kiljak
2
@IceTea, pour vous donner un aperçu / une intuition de votre question. Si vous établissez un graphique par nrapport à n/2vous verrez que les deux forment une ligne droite. Cela les place dans la même classe car ils ont des taux de croissance similaires (pensez-y comme la forme du graphique). De la même façon, si vous vous représentez par log_2rapport à la carte, log_3vous verrez qu'ils prennent tous les deux des «formes similaires» ou des «taux de croissance similaires».
James Oravec
1
@IceTea, l'explication donnée par @Shai et @James est plus précise, n/2 or 2n or n+2 or naura une ligne différente dans le graphique mais ils auront le même taux de croissance, ce qui signifie que tous suivront une croissance linéaire.
Naresh Joshi
2
Que diriez-vous du cas où nous avons deux boucles imbriquées, mais le deuxième itérateur dépend du premier, cette dépendance affecte-t-elle la complexité temporelle?
Bionix1441
131

Si vous aviez une fonction qui prend:

1 millisecond to complete if you have 2 elements.
2 milliseconds to complete if you have 4 elements.
3 milliseconds to complete if you have 8 elements.
4 milliseconds to complete if you have 16 elements.
...
n milliseconds to complete if you have 2^n elements.

Ensuite, cela prend du temps log 2 (n). La notation Big O , en gros, signifie que la relation ne doit être vraie que pour les grands n, et que les facteurs constants et les termes plus petits peuvent être ignorés.

Mark Byers
la source
log2 (n) est-il le même que o (log n)?
Sven van den Boogaart,
Oui, voir le commentaire de nawfal pour une autre réponse ici: (copier-coller) - dans le contexte de programmation, la base de log est 2 (pas 10), donc O (log n) est comme 1 sec pour 10 éléments, 2 sec pour 20 , 3 pour 40 etc
Andrejs
@SvenvandenBoogaart, l'exemple de cette solution illustre log_2, qui est dans la classe O(log(n)). Il y en a beaucoup d'autres dans la même classe de O(log(n))ie log_xx > 1
James Oravec
@Andrejs, votre commentaire so O(log n) scales like 1 sec for 10 elements, 2 sec for 20, 3 for 40 etcest inexact. Ce modèle / classe correspondrait / ne s'alignerait O(n)pas O(log(n)). Si quelqu'un était intéressé, log_10un exemple équivalent serait 1 seconde pour 10 éléments, 2 secondes pour 100, 3 pour 1000, etc.
James Oravec
99

Le temps d'exécution logarithmique ( O(log n)) signifie essentiellement que le temps d'exécution augmente proportionnellement au logarithme de la taille d'entrée - par exemple, si 10 éléments prennent au maximum un certain temps x, et 100 éléments prennent au maximum, disons 2x, et 10000 éléments prend tout au plus 4x, alors ça ressemble à une O(log n)complexité temporelle.

Anon.
la source
1
+1, mais vous devez vraiment souligner que c'est log2, pas log10.
Adriano Varoli Piazza
62
log2 ou log10 n'est pas pertinent. Ils ne diffèrent que par un facteur d'échelle, ce qui les rend du même ordre, c'est-à-dire qu'ils croissent toujours au même rythme.
Noldorin
17
Ce qui est amusant avec les logarithmes, c'est que lors de la comparaison des hauteurs relatives, la base exacte que vous utilisez n'a pas d'importance. log 10,000 / log 100est 2 quelle que soit la base que vous utilisez.
Anon.
12
Pour être précis, O (lg n) signifie que le temps d'exécution est au plus proportionnel à lg n. Ce que vous décrivez est Theta (lg n).
1
@rgrig: C'est vrai. J'en ai édité quelques-uns "at mosts" pour indiquer la nature de la limite supérieure du big-O.
Anon.
95

Le logarithme

Ok, essayons de bien comprendre ce qu'est un logarithme.

Imaginez que nous avons une corde et que nous l'avons attachée à un cheval. Si la corde est directement attachée au cheval, la force que le cheval devrait retirer (par exemple, d'un homme) est directement 1.

Imaginez maintenant que la corde soit enroulée autour d'un poteau. Le cheval qui s'éloignera devra maintenant tirer plusieurs fois plus fort. Le nombre de fois dépendra de la rugosité de la corde et de la taille du poteau, mais supposons que cela multipliera sa force par 10 (lorsque la corde fait un tour complet).

Maintenant, si la corde est bouclée une fois, le cheval devra tirer 10 fois plus fort. Si l'humain décide de rendre les choses vraiment difficiles pour le cheval, il peut à nouveau enrouler la corde autour d'un poteau, augmentant sa force de 10 fois supplémentaires. Une troisième boucle augmentera à nouveau la force de 10 fois.

entrez la description de l'image ici

Nous pouvons voir que pour chaque boucle, la valeur augmente de 10. Le nombre de tours requis pour obtenir n'importe quel nombre est appelé le logarithme du nombre, c'est-à-dire que nous avons besoin de 3 postes pour multiplier votre force par 1000 fois, 6 postes pour multiplier votre force par 1 000 000.

3 est le logarithme de 1 000 et 6 est le logarithme de 1 000 000 (base 10).

Que signifie donc O (log n)?

Dans notre exemple ci-dessus, notre «taux de croissance» est O (log n) . Pour chaque boucle supplémentaire, la force que notre corde peut gérer est 10 fois plus:

Turns | Max Force
  0   |   1
  1   |   10
  2   |   100
  3   |   1000
  4   |   10000
  n   |   10^n

Maintenant, l'exemple ci-dessus a utilisé la base 10, mais heureusement, la base du journal est insignifiante lorsque nous parlons de la notation du grand o.

Imaginons maintenant que vous essayez de deviner un nombre compris entre 1 et 100.

Your Friend: Guess my number between 1-100! 
Your Guess: 50
Your Friend: Lower!
Your Guess: 25
Your Friend: Lower!
Your Guess: 13
Your Friend: Higher!
Your Guess: 19
Your Friend: Higher!
Your Friend: 22
Your Guess: Lower!
Your Guess: 20
Your Friend: Higher!
Your Guess: 21
Your Friend: YOU GOT IT!  

Maintenant, il vous a fallu 7 suppositions pour bien faire les choses. Mais quelle est la relation ici? Quel est le plus grand nombre d'articles que vous pouvez deviner à partir de chaque supposition supplémentaire?

Guesses | Items
  1     |   2
  2     |   4
  3     |   8
  4     |   16
  5     |   32
  6     |   64
  7     |   128
  10    |   1024

En utilisant le graphique, nous pouvons voir que si nous utilisons une recherche binaire pour deviner un nombre compris entre 1 et 100, cela nous prendra au plus 7 tentatives. Si nous avions 128 nombres, nous pourrions également deviner le nombre en 7 tentatives, mais 129 nombres nous prendront au plus 8 tentatives (en relation avec les logarithmes, ici nous aurions besoin de 7 suppositions pour une plage de 128 valeurs, 10 suppositions pour une plage de 1024 valeurs 7 est le logarithme de 128, 10 est le logarithme de 1024 (base 2)).

Notez que j'ai mis en gras «tout au plus». La notation Big-O fait toujours référence au pire des cas. Si vous êtes chanceux, vous pourriez deviner le nombre en une seule tentative et donc le meilleur cas est O (1), mais c'est une autre histoire.

Nous pouvons voir que pour chaque supposition, notre ensemble de données diminue. Une bonne règle de base pour identifier si un algorithme a un temps logarithmique consiste à voir si l'ensemble de données diminue d'un certain ordre après chaque itération

Et O (n log n)?

Vous rencontrerez éventuellement un algorithme O temps linéaire (n log (n)) . La règle générale ci-dessus s'applique à nouveau, mais cette fois, la fonction logarithmique doit s'exécuter n fois, par exemple en réduisant la taille d'une liste n fois , ce qui se produit dans des algorithmes comme un mergesort.

Vous pouvez facilement identifier si le temps algorithmique est n log n. Recherchez une boucle externe qui itère dans une liste (O (n)). Ensuite, regardez s'il y a une boucle intérieure. Si la boucle interne coupe / réduit l'ensemble de données à chaque itération, cette boucle est (O (log n)), et donc l'algorithme global est = O (n log n) .

Avertissement: L'exemple du logarithme de la corde a été tiré de l'excellent livre Delight du mathématicien de W.Sawyer .

benscabbia
la source
Non In our example above, our 'growth rate' is O(log n). For every additional loop, the force our rope can handle is 10 times more, soutenu par un graphique qui montre n == nombre de boucles et our 'growth rate'=> 10 ^ n, qui n'est PAS log n. L'exemple peut être corrigé en faisant n=# horses, ce qui nécessite des boucles log n pour se restreindre. De mauvais exemples pédogogiques produisent des étudiants qui croient seulement comprendre.
psimpson
56

Vous pouvez penser à O (log N) intuitivement en disant que le temps est proportionnel au nombre de chiffres dans N.

Si une opération effectue un travail à temps constant sur chaque chiffre ou bit d'une entrée, l'opération entière prendra un temps proportionnel au nombre de chiffres ou de bits dans l'entrée, et non à l'amplitude de l'entrée; ainsi, O (log N) plutôt que O (N).

Si une opération prend une série de décisions à temps constant dont chacune réduit de moitié (réduit d'un facteur 3, 4, 5 ..) la taille de l'entrée à considérer, l'ensemble prendra un temps proportionnel au log base 2 (base 3 , base 4, base 5 ...) de la taille N de l'entrée, plutôt que d'être O (N).

Etc.

l'ombre de la lune
la source
7
Je suis assez précis et plus facile à saisir que la plupart des explications.
T.
c'est une explication log<sub>10</sub> N, n'est-ce pas?
LiuYan 刘 研
1
@LiuYan 刘 研 ils n'ont pas dit dans quelle base se trouvait le nombre de chiffres. Quoi qu'il en soit, log₂ (n) = log₁₀ (n) / log₁₀ (2) et 1 / log₁₀ (2) est donc un multiplicateur constant, le même principe s'appliquant à toutes les autres bases. Cela montre deux choses. Premièrement, le principe de l'ombre lunaire s'applique quelle que soit la base (bien que plus la base est basse, moins il y a de "jags" dans l'estimation) et aussi que O (log n) est O (log n) quelle que soit la base du calcul qui vous a conduit à cette conclusion. .
Jon Hanna
"proportionnel" ... "dont chacun réduit de moitié la taille de l'entrée" ??????
csguy
52

La meilleure façon dont j'ai toujours eu à visualiser mentalement un algorithme qui s'exécute en O (log n) est la suivante:

Si vous augmentez la taille du problème d'une quantité multiplicative (c'est-à-dire multipliez sa taille par 10), le travail n'est augmenté que d'une quantité additive.

En appliquant cela à votre question d'arbre binaire, vous avez donc une bonne application: si vous doublez le nombre de nœuds dans un arbre binaire, la hauteur n'augmente que de 1 (une quantité additive). Si vous le doublez à nouveau, il n'a encore augmenté que de 1. (Évidemment, je suppose qu'il reste équilibré et tel). De cette façon, au lieu de doubler votre travail lorsque la taille du problème est multipliée, vous ne faites que très légèrement plus de travail. C'est pourquoi les algorithmes O (log n) sont géniaux.

DivineWolfwood
la source
52

Je vous recommande d'abord de lire le livre suivant;

Algorithmes (4e édition)

Voici quelques fonctions et leurs complexités attendues. Les nombres indiquent les fréquences d'exécution des instructions .

Voici quelques fonctions et leurs complexités attendues

Le graphique de complexité Big-O est également tiré de bigocheatsheet Graphique de complexité Big-O

Enfin une vitrine très simple montre comment il est calculé;

Anatomie des fréquences d'exécution des instructions d'un programme.

Analyse du temps d'exécution d'un programme (exemple).

Analyser le temps d'exécution d'un programme

Teoman shipahi
la source
5
Je ne mettrais pas O (n log n) dans le mauvais panier. Il appartient au juste .
André Werlang
Lorsque vous consultez le tableau de complexité big-O (ci-dessus), vous devez vous rappeler que O (n) est le point linéaire réel, pas le bord rose / orange. @Andre C'est pourquoi O (n log n) est correctement marqué dans la "mauvaise" plage de performances, c'est une performance pire que linéaire.
JavaBeast
@JavaBeast correct, alors que les performances de O (n log n) sont techniquement moins bonnes que O (n), reportez-vous au tableau ci-dessus, qui en présente une bonne comparaison (voir la croissance des deux). otoh le graphique, provenant d'une source différente, est contradictoire car il met O (1) et O (log n) dans le même bon / excellent. leur ordre relatif de croissance est comparable à O (n) et O (n log n). tl; dr; O (n log n) n'est pas excellent, mais est loin d'être mauvais.
André Werlang
1
Cette réponse est fausse! Il suppose que N = N * N. En fait N = N! Votre exemple est en fait N cube. Vous faites de même dans votre graphique. Votre O (n) devrait en fait être le fossé entre horrible et mauvais. Preuve mathématique: Vous dites que la boucle for est constante avec O (1). C'est ce que le 1 signifie vraiment, ne dépendant pas de N. Cela signifie simplement non variable. Mais elle est variable car elle dépend de N. Deux fois N et la moitié du temps. Par conséquent, il n'est pas valide. Si c'est de ce livre, ne l'achetez pas! Le graphique de code que vous avez montré n'est pas réel, c'est une blague, regardez, "Theesome", cela signifie trois personnes ayant des relations sexuelles à la fois! OMG
jgmjgm
1
O (n) ne devrait-il pas être sur la diagonale?
gyosifov
46

Qu'est-ce que le log b (n)?

C'est le nombre de fois que vous pouvez couper un journal de longueur n à plusieurs reprises en b parties égales avant d'atteindre une section de taille 1.

Chad Brewbaker
la source
Excellent commentaire! C'est concis et c'est exactement la réponse que je recherche.
DennisL
18

Les algorithmes de division et de conquête ont généralement un logncomposant pour le temps d'exécution. Cela vient de la réduction de moitié répétée de l'entrée.

Dans le cas d'une recherche binaire, à chaque itération, vous jetez la moitié de l'entrée. Il convient de noter qu'en notation Big-O, log est log base 2.

Edit: Comme indiqué, la base de journal n'a pas d'importance, mais lors de la dérivation des performances Big-O d'un algorithme, le facteur de journal proviendra de la réduction de moitié, d'où la raison pour laquelle je le considère comme la base 2.

David Kanarek
la source
2
Pourquoi est-il log base 2? Dans le tri rapide randomisé par exemple, je ne pense pas que ce soit la base 2. Pour autant que je sache, la base n'a pas d'importance, comme la base de log a (n) = log2 (n) / log2 (a), donc chaque logarithme est différent d'un autre par une constante, et les constantes sont ignorées en notation big-o. En fait, écrire la base d'un journal en notation big-o est une erreur à mon avis, car vous écrivez une constante.
IVlad
Il est très vrai qu'il peut être converti en n'importe quelle base et cela n'a pas d'importance, mais si vous essayez de dériver les performances de Big-O et que vous voyez une diminution constante de moitié, cela aide à comprendre que vous ne verrez pas la base de journal 10 reflétée dans le code.
David Kanarek
Un côté: dans des choses telles que les arbres B, où les nœuds ont un fan-out de plus de 2 (c'est-à-dire "plus large" qu'un arbre binaire), vous verrez toujours une croissance O (logn), car elle est toujours divisée et -conquer, mais la base du journal sera liée au fan-out.
Roger Lipscombe
La digression sur le journal 2 a été très utile, en fait.
Dan Rosenstark
15

Mais qu'est-ce que O (log n) exactement? Par exemple, que signifie dire que la hauteur d'un> arbre binaire complet est O (log n)?

Je reformulerais ceci comme «la hauteur d'un arbre binaire complet est log n». Calculer la hauteur d'un arbre binaire complet serait O (log n), si vous descendiez pas à pas.

Je ne peux pas comprendre comment identifier une fonction avec un temps logarithmique.

Le logarithme est essentiellement l'inverse de l'exponentiation. Donc, si chaque «étape» de votre fonction élimine un facteur d'éléments de l'ensemble d'éléments d'origine, c'est un algorithme de temps logarithmique.

Pour l'exemple de l'arborescence, vous pouvez facilement voir que la réduction d'un niveau de nœuds réduit un nombre exponentiel d'éléments lorsque vous continuez à parcourir. L'exemple populaire de recherche dans un annuaire téléphonique trié par nom est essentiellement équivalent à parcourir un arbre de recherche binaire (la page du milieu est l'élément racine, et vous pouvez déduire à chaque étape si vous allez à gauche ou à droite).

user2421873
la source
3
+1 pour mentionner "le logarithme est essentiellement l'inverse de l'exponentiation".
talonx
12

Ces 2 cas prendront du temps O (log n)

case 1: f(int n) {
      int i;
      for (i = 1; i < n; i=i*2)
        printf("%d", i);
    }


 case 2  : f(int n) {
      int i;
      for (i = n; i>=1 ; i=i/2)
        printf("%d", i);
    }
Ravi Bisla
la source
Je suis sûr que je manque quelque chose, mais ne serais-je pas toujours à zéro et les boucles fonctionnent-elles pour toujours dans ces deux cas, puisque 0 * 2 = 0 et 0/2 = 0?
dj_segfault
2
@dj_segfault, c'était mon erreur. Je pense que ça a du sens maintenant :) :)
Ravi Bisla
@RaviBisla D'autres réponses indiquent qu'une entrée de 10 prendrait 1 fois autant que 10 boucles, et une entrée de 100 prendrait 3 fois le temps d'entrée de 1, ce qui n'est certainement pas le cas avec ces exemples. stackoverflow.com/a/2307330/1667868
Sven van den Boogaart
12

O (log n) est un peu trompeur, plus précisément c'est O (log 2 n), c'est-à-dire (logarithme avec base 2).

La hauteur d'un arbre binaire équilibré est O (log 2 n), car chaque nœud a deux (notez les "deux" comme dans le journal 2 n) nœuds enfants. Ainsi, un arbre à n nœuds a une hauteur de log 2 n.

Un autre exemple est la recherche binaire, qui a un temps d'exécution de O (log 2 n) car à chaque étape, vous divisez l'espace de recherche par 2.

stmax
la source
4
O (log n) est du même ordre que O (ld n) ou O (LN n). Ils sont proportionnels. Je comprends qu'à des fins d'apprentissage, il est plus facile d'utiliser ld.
helios
4
"plus précisément, c'est O (ld n)" - Non, ce n'est pas le cas: tous les journaux sont du même ordre (chacun ne différant des autres que par un facteur d'échelle constant, qui est ignoré / ignorable).
ChrisW
1
vous avez raison chris, très mauvaise formulation. aurait dû le dire comme Helios. cela aide à apprendre / comprendre mais finalement tous les journaux sont du même ordre.
stmax
10

O(log n) fait référence à une fonction (ou algorithme, ou étape d'un algorithme) fonctionnant dans un laps de temps proportionnel au logarithme (généralement en base 2 dans la plupart des cas, mais pas toujours, et en tout état de cause, cela n'est pas significatif par la notation big-O *) de la taille de l'entrée.

La fonction logarithmique est l'inverse de la fonction exponentielle. Autrement dit, si votre entrée croît de façon exponentielle (plutôt que de façon linéaire, comme vous le pensez normalement), votre fonction se développe de façon linéaire.

O(log n)les temps d'exécution sont très courants dans toute sorte d'application de division et de conquête, car vous coupez (idéalement) le travail en deux à chaque fois. Si dans chacune des étapes de division ou de conquête, vous effectuez un travail à temps constant (ou un travail qui n'est pas à temps constant, mais avec un temps qui croît plus lentement que O(log n)), alors votre fonction entière l'est O(log n). Il est assez courant que chaque étape nécessite un temps linéaire à la place; cela équivaudra à une complexité temporelle totale de O(n log n).

La complexité du temps d'exécution de la recherche binaire en est un exemple O(log n). En effet, dans la recherche binaire, vous ignorez toujours la moitié de votre entrée à chaque étape ultérieure en divisant le tableau en deux et en vous concentrant uniquement sur une moitié à chaque étape. Chaque étape est à temps constant, car dans la recherche binaire, vous n'avez qu'à comparer un élément avec votre clé afin de savoir quoi faire ensuite, quelle que soit la taille du tableau que vous envisagez à tout moment. Vous effectuez donc approximativement les étapes log (n) / log (2).

La complexité du temps de fonctionnement du tri par fusion en est un exemple O(n log n). Cela est dû au fait que vous divisez le tableau en deux à chaque étape, ce qui donne un total d'environ log (n) / log (2) étapes. Cependant, à chaque étape, vous devez effectuer des opérations de fusion sur tous les éléments (qu'il s'agisse d'une opération de fusion sur deux sous-listes d'éléments n / 2 ou de deux opérations de fusion sur quatre sous-listes d'éléments n / 4, cela n'a pas d'importance car cela ajoute à la nécessité de faire cela pour n éléments à chaque étape). Ainsi, la complexité totale est O(n log n).

* N'oubliez pas que la notation big-O, par définition , n'a pas d'importance. De même, par le changement de règle de base pour les logarithmes, la seule différence entre les logarithmes de différentes bases est un facteur constant.

Platine Azure
la source
La note finale * a résolu ma confusion sur les logarithmes basés sur 2 ou 10 :) Merci beaucoup.
yahya
9

Cela signifie simplement que le temps nécessaire à cette tâche augmente avec log (n) (exemple: 2s pour n = 10, 4s pour n = 100, ...). Lisez les articles de Wikipedia sur l' algorithme de recherche binaire et la notation Big O pour plus de précisions.

Valentin Rocher
la source
9

Autrement dit: à chaque étape de votre algorithme, vous pouvez réduire le travail de moitié. (Asymptotiquement équivalent aux troisième, quatrième, ...)

Brian R. Bondy
la source
2
Cette réponse est très imprécise. Tout d'abord, vous pouvez penser à réduire le travail de moitié uniquement dans le cas du logarithme en base 2. C'est vraiment incroyable de voir comment cette réponse (et la plupart des réponses à la question d'origine) a reçu autant de votes positifs. "(Asymptotiquement équivalent au troisième, quatrième, ...)"? Pourquoi répondre à une question si vous n'avez pas le temps?
nbro
8

Si vous tracez une fonction logarithmique sur une calculatrice graphique ou quelque chose de similaire, vous verrez qu'elle augmente très lentement - encore plus lentement qu'une fonction linéaire.

C'est pourquoi les algorithmes à complexité logarithmique temporelle sont très recherchés: même pour de très gros n (disons n = 10 ^ 8, par exemple), ils fonctionnent plus qu'acceptablement.

Hadewijch Debaillie
la source
7

Mais quel est exactement O (log n)

Ce que cela signifie précisément, c'est "comme ntend vers infinity, le timetend vers a*log(n)aest un facteur d'échelle constant".

Ou en fait, cela ne signifie pas tout à fait cela; plus probablement, cela signifie quelque chose comme " timedivisé par a*log(n)tend vers 1".

"Tends vers" a le sens mathématique habituel de 'analyse': par exemple, que "si vous choisissez n'importe quelle constante non nulle arbitrairement petite k, alors je peux trouver une valeur correspondante Xtelle qu'elle ((time/(a*log(n))) - 1)soit inférieure à celle kde toutes les valeurs nsupérieures à X."


En termes simples, cela signifie que l'équation du temps peut avoir d'autres composants: par exemple, elle peut avoir un temps de démarrage constant; mais ces autres composantes pâle vers l'insignifiance pour les grandes valeurs de n, et le a * log (n) est le terme dominant pour le grand n.

Notez que si l'équation était, par exemple ...

temps (n) = a + b log (n) + c n + d n n

... alors ce serait O (n au carré) car, quelles que soient les valeurs des constantes a, b, c et d non nulles, le d*n*nterme dominerait toujours les autres pour toute valeur suffisamment grande de n.

C'est ce que signifie la notation du bit O: cela signifie "quel est l'ordre de terme dominant pour tout n suffisamment grand".

ChrisW
la source
C'est faux. en.wikipedia.org/wiki/…
Michael Graczyk
7

Je peux ajouter quelque chose d'intéressant, que j'ai lu il y a longtemps dans un livre de Kormen et etc. Maintenant, imaginez un problème, où nous devons trouver une solution dans un espace à problème. Cet espace problématique doit être fini.

Maintenant, si vous pouvez prouver qu'à chaque itération de votre algorithme, vous coupez une fraction de cet espace, ce qui n'est pas moins qu'une certaine limite, cela signifie que votre algorithme s'exécute en temps O (logN).

Je dois souligner que nous parlons ici d'une limite de fraction relative, pas absolue. La recherche binaire est un exemple classique. À chaque étape, nous jetons la moitié de l'espace problématique. Mais la recherche binaire n'est pas le seul exemple de ce genre. Supposons que vous ayez prouvé d'une manière ou d'une autre qu'à chaque étape, vous jetez au moins 1/128 d'espace problématique. Cela signifie que votre programme est toujours en cours d'exécution au moment O (logN), bien que beaucoup plus lent que la recherche binaire. C'est un très bon indice pour l'analyse d'algorithmes récursifs. Il peut souvent être prouvé qu'à chaque étape la récursivité n'utilisera pas plusieurs variantes, ce qui conduit à la coupure d'une fraction dans l'espace du problème.

SPIRiT_1984
la source
6

Je peux donner un exemple de boucle for et peut-être une fois saisi le concept, il sera peut-être plus simple à comprendre dans différents contextes.

Cela signifie que dans la boucle, le pas croît de façon exponentielle. Par exemple

for (i=1; i<=n; i=i*2) {;}

La complexité en notation O de ce programme est O (log (n)). Essayons de le parcourir à la main (n étant compris entre 512 et 1023 (à l'exception de 1024):

step: 1   2   3   4   5    6    7    8     9     10
   i: 1   2   4   8   16   32   64   128   256   512

Bien que n soit compris entre 512 et 1023, seulement 10 itérations ont lieu. En effet, le pas dans la boucle croît de façon exponentielle et ne prend donc que 10 itérations pour atteindre la terminaison.

Le logarithme de x (à la base de a) est la fonction inverse de a ^ x.

C'est comme dire que le logarithme est l'inverse de l'exponentielle.

Essayez maintenant de voir les choses de cette façon, si l'exponentielle croît très rapidement, le logarithme croît (inversement) très lentement.

La différence entre O (n) et O (log (n)) est énorme, similaire à la différence entre O (n) et O (a ^ n) (a étant une constante).

Ely
la source
6

En fait, si vous avez une liste de n éléments et créez un arbre binaire à partir de cette liste (comme dans l'algorithme de division et de conquête), vous continuerez à diviser par 2 jusqu'à atteindre des listes de taille 1 (les feuilles).

À la première étape, vous divisez par 2. Vous avez alors 2 listes (2 ^ 1), vous divisez chacune par 2, vous avez donc 4 listes (2 ^ 2), vous divisez à nouveau, vous avez 8 listes (2 ^ 3 ) et ainsi de suite jusqu'à ce que la taille de votre liste soit 1

Cela vous donne l'équation:

n/(2^steps)=1 <=> n=2^steps <=> lg(n)=steps

(vous prenez le lg de chaque côté, lg étant la base du journal 2)

Dinaiz
la source
2
Jusqu'à ce que certains logiciels malveillants commencent à insérer une nouvelle liste de longueur x à deux niveaux avant que les nœuds ne quittent. Ensuite, cela semblera être une boucle infinie ...
Francis Cugler
1
Je n'ai pas eu ton commentaire. Mon explication est-elle fausse?
Dinaiz
1
Je faisais seulement une blague hypothétique. Je ne voulais vraiment rien dire par là.
Francis Cugler
6

Chaque fois que nous écrivons un algorithme ou un code, nous essayons d'analyser sa complexité asymptotique. Il est différent de sa complexité temporelle .

La complexité asymptotique est le comportement du temps d'exécution d'un algorithme tandis que la complexité temporelle est le temps d'exécution réel. Mais certaines personnes utilisent ces termes de manière interchangeable.

Parce que la complexité temporelle dépend de divers paramètres à savoir.
1. Système physique
2. Langage de programmation
3. Style de codage
4. Et bien plus encore ......

Le temps d'exécution réel n'est pas une bonne mesure pour l'analyse.


Au lieu de cela, nous prenons la taille d'entrée comme paramètre, car quel que soit le code, l'entrée est la même. Le temps d'exécution est donc fonction de la taille d'entrée.

Voici un exemple d'algorithme de temps linéaire


Recherche linéaire
Étant donné n éléments d'entrée, pour rechercher un élément dans le tableau, vous avez besoin d' au plus 'n' comparaisons . En d'autres termes, quel que soit le langage de programmation que vous utilisez, le style de codage que vous préférez, le système sur lequel vous l'exécutez. Dans le pire des cas, il ne nécessite que n comparaisons. Le temps d'exécution est linéairement proportionnel à la taille d'entrée.

Et ce n'est pas seulement une recherche, quel que soit le travail (incrémenter, comparer ou n'importe quelle opération), c'est une fonction de la taille d'entrée.

Ainsi, lorsque vous dites qu'un algorithme est O (log n), cela signifie que le temps d'exécution est log fois la taille d'entrée n.

À mesure que la taille d'entrée augmente, le travail effectué (ici le temps d'exécution) augmente (d'où la proportionnalité).

      n      Work
      2     1 units of work
      4     2 units of work
      8     3 units of work

Voyez comme la taille d'entrée a augmenté, le travail effectué est augmenté et il est indépendant de toute machine. Et si vous essayez de découvrir la valeur des unités de travail, cela dépend en fait de ces paramètres spécifiés ci-dessus. Cela changera en fonction des systèmes et de tout.

Sanjay Kumar
la source
5

Arbre

log x to base b = y est l'inverse de b^y = x

Si vous avez un arbre M-aire de profondeur d et de taille n, alors:

  • traversant l'arbre entier ~ O (M ^ d) = O (n)

  • Marcher un seul chemin dans l'arbre ~ O (d) = O (log n à la base M)

Khaled.K
la source
5

En technologie de l'information, cela signifie que:

  f(n)=O(g(n)) If there is suitable constant C and N0 independent on N, 
  such that
  for all N>N0  "C*g(n) > f(n) > 0" is true.

Et il semble que cette notation ait été principalement empruntée aux mathématiques.

Dans cet article, il y a une citation: DE Knuth, "BIG OMICRON ET BIG OMEGA ET BIG THETA", 1976 :

Sur la base des questions discutées ici, je propose que les membres de SIGACT et les rédacteurs en chef des revues d'informatique et de mathématiques adoptent les notations définies ci-dessus, à moins qu'une meilleure alternative ne puisse être trouvée assez rapidement .

Aujourd'hui, c'est 2016, mais nous l'utilisons encore aujourd'hui.


En analyse mathématique, cela signifie que:

  lim (f(n)/g(n))=Constant; where n goes to +infinity

Mais même dans l'analyse mathématique, ce symbole était parfois utilisé pour signifier "C * g (n)> f (n)> 0".

Comme je le sais de l'université, le symbole a été introduit par le mathématicien allemand Landau (1877-1938)

bruziuz
la source
4

L'exemple binaire complet est O (ln n) car la recherche ressemble à ceci:

1 2 3 4 5 6 7 8 9 10 11 12

La recherche de 4 donne 3 résultats: 6, 3 puis 4. Et log2 12 = 3, ce qui correspond bien au nombre de résultats lorsque cela est nécessaire.

Amirshk
la source
merci pour l'exemple. Il indique clairement comment notre algorithme peut utiliser le temps logarithmique dans la méthode de division et de conquête.
Abc
Donc, si c'est une boucle de n / 2, c'est toujours log (n)?
Gil Beyruth
3

Si vous cherchez une réponse basée sur l'intuition, j'aimerais vous proposer deux interprétations.

  1. Imaginez une colline très haute avec une base très large également. Pour atteindre le sommet de la colline, il y a deux façons: l'une est un chemin dédié qui tourne en spirale autour de la colline pour atteindre le sommet, l'autre: une petite terrasse comme des sculptures découpées pour fournir un escalier. Or si la première voie atteint en temps linéaire O (n), la seconde est O (log n).

  2. Imaginez un algorithme, qui accepte un entier, ncomme entrée et se termine en temps proportionnel à nalors il est O (n) ou thêta (n) mais s'il s'exécute en proportion temporelle à number of digits or the number of bits in the binary representation on numberalors l'algorithme s'exécute en O (log n) ou thêta (log n) temps.

mickeymoon
la source
veuillez modifier. a "O (n) ou thêta (n)" dans les deux scénarios ...? De plus, j'ai beaucoup entendu cela, la taille par rapport aux # chiffres. Sommes-nous en train de dire taille === 128 pour n = 10000000 et chiffres === 8 pour n = 10000000? Veuillez expliquer.
Cody
2

Les algorithmes du paradigme Divide and Conquer sont de complexité O (logn). Un exemple ici, calculez votre propre fonction de puissance,

int power(int x, unsigned int y)
{
    int temp;
    if( y == 0)
        return 1;
    temp = power(x, y/2);
    if (y%2 == 0)
        return temp*temp;
    else
        return x*temp*temp;
}

depuis http://www.geeksforgeeks.org/write-ac-program-to-calculate-powxn/

kiriloff
la source