La complexité algorithmique de la suite de Fibonacci
Je comprends Big-O de la notation, mais je ne sais pas comment le calculer pour de nombreuses fonctions. En particulier, j'ai été à essayer de comprendre la complexité de calcul de la version naïve de la suite de Fibonacci:
int Fibonacci(int n)
{
if (n <= 1)
return n;
else
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
Qu'est-ce que la complexité de calcul de la suite de Fibonacci et comment est-il calculé?
- les Bonnes réponses ici.
- Voir la matrice de la forme de l'article ici: en.wikipedia.org/wiki/Fibonacci_number . en procédant de cette matrice ^ n (dans une manière intelligente de), vous pouvez calculer Fib(n) en temps O(lg n). Le truc, c'est de faire la fonction de puissance. Theres une très bonne conférence sur iTunesU à propos de ce problème et comment le résoudre en temps O(lg n). Le cours d'intro à des algorithmes de MIT conférence 3 (son absolument libre de sorte de vérifier si vous êtes intéressés)
- Ni des commentaires ci-dessus l'adresse de la question, qui est de parler de la complexité de calcul de la version naïve (posté dans le code), pas plus intelligent versions comme la matrice de la forme ou de la non-récursive de calcul.
- Une très belle vidéo ici qui parle à la fois de la limite inférieure de la complexité(2^n/2) et la limite supérieure de la complexité(2^n) de récursive de la mise en œuvre.
- Une note de la requête: la naïfs la mise en œuvre de la suite de Fibonacci être itératif ou récursive?
Vous devez vous connecter pour publier un commentaire.
Le modèle de la fonction de temps pour calculer
Fib(n)
comme la somme des temps de calcul de l'Fib(n-1)
plus le temps de calculerFib(n-2)
plus le temps d'ajouter de l'ensemble (O(1)
). C'est en supposant que les évaluations de la mêmeFib(n)
prendre le même temps - c'est à dire pas de memoization est utiliser.T(n<=1) = O(1)
T(n) = T(n-1) + T(n-2) + O(1)
Vous résoudre cette relation de récurrence (à l'aide des fonctions génératrices, par exemple) et vous aurez la réponse.
Alternativement, vous pouvez dessiner la récursivité de l'arbre, ce qui aura de la profondeur
n
et intuitivement comprendre que cette fonction est asymptotiquementO(2
n
)
. Ensuite, vous pouvez prouver votre conjecture par induction.Base:
n = 1
est évidentAssumer
T(n-1) = O(2
n-1
)
, doncT(n) = T(n-1) + T(n-2) + O(1)
est égal àT(n) = O(2
n-1
) + O(2
n-2
) + O(1) = O(2
n
)
Toutefois, comme indiqué dans un commentaire, ce n'est pas le serré lié. Un fait intéressant à propos de cette fonction est que le T(n) est asymptotiquement au comme la valeur de
Fib(n)
puisque les deux sont définis commef(n) = f(n-1) + f(n-2)
.Les feuilles de la récursivité de l'arbre renvoie toujours 1. La valeur de
Fib(n)
est la somme de toutes les valeurs retournées par les feuilles de la récursivité de l'arbre, qui est égal au nombre de feuilles. Puisque chaque feuille va prendre O(1) pour calculer,T(n)
est égal àFib(n) x O(1)
. Par conséquent, le resserrement lié à cette fonction est la suite de Fibonacci lui-même (~θ(1.6
n
)
). Vous pouvez trouver cette serré lié en utilisant des fonctions comme je l'avais mentionné ci-dessus.T(n-1) = O(2^(n-1))
, mais PAS queT(n-2) = O(2^(n-2))
qui Mehrdad utilise dans la dernière étape de la preuve. Nous ne savons pasT(n-2) = O(2^(n-2))
. La solution la plus simple pour cela est d'utiliser l'induction, plutôt que partielle. Montrer l'énoncé est vrai pour Fib n ° 1 et Fib#2, alors vous pouvez supposerT(n-2) = O(2^(n-2))
, et la preuve en est titulaire.Il suffit de demander vous-même combien de déclarations ont besoin pour exécuter pour
F(n)
pour terminer.Pour
F(1)
, la réponse est1
(la première partie du conditionnel).Pour
F(n)
, la réponse estF(n-1) + F(n-2)
.Donc la fonction qui satisfait à ces règles? Essayez unn (a > 1):
unn == a(n-1) + a(n-2)
Diviser par un(n-2):
un2 == un + 1
Résoudre pour
a
et vous obtenez(1+sqrt(5))/2 = 1.6180339887
, autrement connu comme l' nombre d'or.Donc ça prend du temps exponentiel.
x
, nous supposons pour n'importe quelle branche de la fib(n), le O(n) estx^n
. Ainsix^n = x^n-1 + x^n-2
.Il y a une très belle discussion de ce problème spécifique au cours au MIT. À la page 5, ils font valoir que, si l'on suppose qu'un ajout d'une unité de calcul, le temps nécessaire pour calculer Fib(N) est très étroitement liée à la suite de Fib(N).
Comme un résultat, vous pouvez passer directement à la très bonne approximation de la suite de Fibonacci:
et de dire, donc, que le pire des cas, les performances de l'algorithme naïf est
PS: Il y a une discussion de la fermé forme d'expression de la n-ième nombre de Fibonacci sur Wikipedia si vous souhaitez plus d'informations.
Je suis d'accord avec pgaur et rickerbh, récursif de fibonacci de la complexité est O(2^n).
Je suis venu à la même conclusion par un peu simpliste, mais je crois toujours valide le raisonnement.
D'abord, il s'agit de déterminer combien de fois récursif de la fonction de fibonacci F() à partir de maintenant ) est appelée lors du calcul du n-ième nombre de fibonacci. Si elle est appelée une fois par numéro dans la séquence de 0 à n, alors nous avons O(n), s'il est appelé à la n des temps, pour chaque numéro, alors on obtient O(n*n) ou O(n^2), et ainsi de suite.
Ainsi, lorsque F() est appelée pour un nombre n, le nombre de fois où F() est appelée pour un nombre entre 0 et n-1 grandit à mesure que nous nous approchons de 0.
Comme première impression, il me semble que si on le met dans un mode visuel, le dessin d'une unité en fonction du temps F() est appelée pour un nombre donné, humide obtenir une sorte de forme de pyramide (qui est, si nous centre unités horizontalement). Quelque chose comme ceci:
Maintenant, la question est de savoir quelle est la vitesse de base de cette pyramide élargissant à mesure que n augmente?
Prenons un cas concret, par exemple F(6)
Nous voyons F(0) est appelée 32 fois, ce qui est 2^5, qui, pour cet échantillon est de 2^(n-1).
Maintenant, nous voulons savoir combien de fois F(x) est appelée à tous, et nous pouvons voir le nombre de fois que F(0) est appelée n'est qu'une partie de cela.
Si nous mentalement déplacer tous les *'partir de F(6) F(2) les lignes en F(1), nous voyons que F(1) et F(0) sont maintenant égaux en longueur. Ce qui signifie, le temps total F() est appelée lorsque n=6 est 2x32=64=2^6.
Maintenant, en termes de complexité:
Vous pouvez l'agrandir et avoir un visulization
<
à la fin? Comment avez-vousT(n-1) + T(n-1)
?T(n-1) > T(n-2)
je peux Donc changerT(n-2)
et mettreT(n-1)
. Je ne obtenir une limite supérieure qui est toujours valable pourT(n-1) + T(n-2)
Il est limité à l'extrémité inférieure par
2^(n/2)
et sur l'extrémité supérieure par 2^n (comme indiqué dans d'autres commentaires). Et un fait intéressant de cette récursive de la mise en œuvre, c'est qu'il a un serré asymptotique lié de Fib(n) lui-même. Ces faits peuvent se résumer ainsi:Le resserrement lié peut être réduite à l'aide de son forme fermée si vous le souhaitez.
La preuve réponses sont bonnes, mais je dois toujours faire un peu d'itérations à la main pour vraiment me convaincre. Donc, j'ai fait un petit appel de l'arbre sur mon tableau blanc, et a commencé à compter les nœuds. J'ai divisé mon compte dans le total des nœuds, les nœuds feuilles, et de l'intérieur des nœuds. Voici ce que j'ai:
Ce qui saute immédiatement remarquer que le nombre de nœuds feuilles est
fib(n)
. Ce qui a eu un peu plus d'itérations pour avis est que le nombre de nœuds intérieurs estfib(n) - 1
. Par conséquent, le nombre total de nœuds est2 * fib(n) - 1
.Puisque vous déposez les coefficients de la classification complexité de calcul, la réponse finale est
θ(fib(n))
.1
à un seul accumulateurFib(n)
fois, mais intéressant de noter que c'est toujours exactementθ(Fib(n))
.0
, cependant: la récursivité de la base de cas sont0
et1
, parce qu'ils neFib(n-1) + Fib(n-2)
. Alors, probablement, le3 * Fib(n) - 2
à partir de ce lien seule réponse est plus précis pour le nombre total de nœuds, pas2 * Fib(n) - 1
.Récursive de l'algorithme de complexité temporelle peut être mieux évalué par le dessin de la récursivité de l'arbre, Dans ce cas, la relation de récurrence pour le dessin de la récursivité arbre serait T(n)=T(n-1)+T(n-2)+O(1)
notez que chaque étape prend O(1) la signification de la constante de temps,car il ne fait qu'une comparaison de vérifier la valeur de n dans si bloc.La récursivité de l'arbre ressemblerait
Ici permet de dire que chaque niveau d'au-dessus de l'arbre est désigné par je
par conséquent,
permet de dire à la valeur de i, l'arbre se termine, ce cas serait le cas de la n-i=1, donc i=n-1, ce qui signifie que la hauteur de l'arbre est n-1.
Maintenant essayons de voir comment beaucoup de travail est fait pour chacun des n couches dans l'arbre.Notez que chaque étape prend O(1) dans la relation de récurrence.
depuis i=n-1 est la hauteur de l'arbre le travail effectué à chaque niveau sera
Donc total sera la somme de travail effectué à chaque niveau, par conséquent, il sera 2^0+2^1+2^2+2^3...+2^(n-1) i=n-1.
Par série géométrique de cette somme est de 2^n, et par conséquent le temps total complexité est ici O(2^n)
Bien, selon moi, c'est
O(2^n)
dans cette fonction uniquement de la récursivité, c'est prendre le temps considérable (diviser pour régner). Nous voyons que la fonction ci-dessus continuera dans un arbre jusqu'à ce que les feuilles sont des approches lorsque nous atteignons le niveauF(n-(n-1))
c'est à direF(1)
. Donc, ici, quand nous avons de noter le temps de la complexité rencontrées à chaque profondeur de l'arbre, la somme de la série est:qui est de l'ordre de
2^n [ O(2^n) ]
.http://www.ics.uci.edu/~eppstein/161/960109.html
de temps(n) = 3F(n) - 2
De la naïveté de la récursivité version de Fibonacci est exponentielle par la conception en raison de la répétition dans le calcul:
À la racine vous êtes informatique:
F(n) dépend de F(n-1) et F(n-2)
F(n-1) dépend de F(n-2) et F(n-3)
F(n-2) dépend de F(n-3) et F(n-4)
alors vous êtes d'avoir à chaque niveau 2 appels récursifs qui gaspillent beaucoup de données dans le calcul, la fonction de temps ressemblera à ceci:
T(n) = T(n-1) + T(n-2) + C, avec C constante
T(n-1) = T(n-2) + T(n-3) > T(n-2) puis
T(n) > 2*T(n-2)
...
T(n) > 2^(n/2) * T(1) = O(2^(n/2))
C'est juste une limite inférieure que pour le but de votre analyse devrait être suffisant, mais le temps réel de la fonction est un facteur d'une constante par la même formule de Fibonacci et le forme fermée est connu pour être exponentielle du nombre d'or.
En outre, vous pouvez trouver des versions optimisées de Fibonacci à l'aide de la programmation dynamique comme ceci:
Qui est optimisé et de ne faire que n étapes, mais est aussi exponentielle.
Les fonctions de coût sont définis à partir d'une Entrée de taille pour le nombre d'étapes pour résoudre le problème. Quand vous voyez la version dynamique de Fibonacci (n étapes pour calculer la table) ou la méthode la plus simple de l'algorithme de savoir si un nombre est premier (sqrt(n) pour analyser la validité de diviseurs du nombre). vous pouvez penser que ces algorithmes sont O(n) ou O(sqrt(n)) mais ce n'est tout simplement pas vrai pour la raison suivante:
Le signal d'entrée de l'algorithme est un nombre: n, à l'aide de la notation binaire la taille de saisie pour un entier n est log2(n) puis en faisant un changement de variable de
laissez savoir que le nombre d'étapes en fonction de la taille de saisie
ensuite le coût de votre algorithme en fonction de la taille de saisie est:
et c'est pourquoi le coût est exponentiel.
Effectue cette manière de mieux:
O(n)
, puisque le nombre d'itérations de lawhile
boucle est égale àn
, et il n'y a pas d'autre boucle ou d'un appel récursif. (Prouvant6*n + 4
estO(n)
est trivial si vous connaissez la définition de laO
notation.)O(2^n)
, mais il y a d'autres façons de trier une liste plus efficacement (par exemple tri de la sélection). Je pense que Juliette se pose au sujet de l'ordre de l'algorithme, elle a fourni, qu'elle appelle la "version naïve."O(Fib(n))
lui-même.