Bonjour, voici le pseudo-code pour ma mise en œuvre de recherche binaire:
Input: (A[0...n-1], K)
begin
l ← 0; r ← n-1
while l ≤ r do
m ← floor((l+r)/2)
if K > A[m] then l ← m+1
else if K < A[m] then r ← m-1 else return m
end if
end while
return -1 // key not found
end
Je me demandais juste comment calculer le nombre de comparaisons que cette implémentation ferait dans le pire des cas pour un tableau trié de taille n?
Le nombre de comparaisons serait-il = lg n + 1? ou quelque chose de différent?
Le pire des cas dans ce cas est, si l'élément K n'est pas présent dans A et plus petit que tous les éléments dans A. Ensuite, nous avons deux comparaisons à chaque étape: K > A[m]
Et K < A[m]
.
Pour chaque étape, le tableau est coupé en deux parties, chacune de la taille (n-1)/2
, Nous avons un maximum de log_2(n-1)
étapes.
Cela conduit à un total de comparaisons de 2*log_2(n-1)
, ce qui équivaut effectivement à O(log(n))
.
Une correction très mineure de réponse de hielsnoppe :
Dans un tableau d'éléments n
- (n > 0
), L'élément à comparer est à l'index m = floor((n-1)/2)
. Il y a donc trois possibilités
A[m] < K
, Puis après une comparaison, la recherche se poursuit dans un tableau d'éléments n-1-m = ceiling((n-1)/2)
-.A[m] > K
, Puis après deux comparaisons, la recherche se poursuit dans un tableau d'éléments m
-.A[m] == K
, Alors nous avons terminé après deux comparaisons.Donc, si nous désignons le nombre maximal (pire des cas) de comparaisons pour une recherche dans un tableau d'éléments n
- par C(n)
, nous avons
C(0) = 0
C(n) = max { 1 + C(ceiling((n-1)/2), 2 + C(floor((n-1)/2) }, n > 0
Pour n = 2k+1
Impair, le sol et le plafond sont identiques, donc le maximum est évidemment ce dernier,
C(2k+1) = 2 + C(k)
et même n = 2k
, on trouve
C(2k) = max { 1 + C(k), 2 + C(k-1) }.
Pour n = 2
, Cela se résout en C(2) = 1 + C(1) = 1 + 2 = 3
, pour tout plus grand même n
, le maximum est 2 + C(k-1)
, car pour n >= 1
Nous avoir C(n) <= C(n+1) <= C(n) + 1
.
En évaluant la récursivité pour les premiers n
, nous trouvons
C(0) = 0
C(1) = 2
C(2) = 3
C(3) = C(4) = 4
C(5) = C(6) = 5
C(7) = C(8) = C(9) = C(10) = 6
C(11) = ... = C(14) = 7
C(15) = ... = C(22) = 8
C(23) = ... = C(30) = 9
Donc, par induction, nous prouvons
C(n) = 2k, if 2^k <= n+1 < 2k + 2^(k-1), and
C(n) = 2k+1, if 2^k + 2^(k-1) <= n+1 < 2^(k+1)
ou
C(n) = 2*log2(n+1) + floor(2*(n+1)/(3*2^floor(log2(n+1)))).
Il s'agit d'une limite supérieure exacte.
Selon la page wikipedia sur recherche binaire , la pire des performances de cet algorithme est O(lg n)
, qui mesure le nombre asymptotique de comparaisons nécessaires. Le nombre de comparaisons réel dans le pire des cas serait 2*lg(n-1)
, comme cela a été souligné dans la réponse de @ hielsnoppe.
Le pseudocode dans la question représente l'implémentation typique d'une recherche binaire, donc les complexités de performance attendues sont valables pour un tableau (ou vecteur) de taille n
:
O(1)
O(lg n)
O(lg n)
En y regardant de plus près, il y a deux problèmes avec le pseudocode dans la question:
if K > A[m] then return l ← m+1
Doit indiquer if K > A[m] then l ← m+1
. Vous ne pouvez pas encore revenirm ← floor((l+r)/2)
peut provoquer un débordement si les nombres sont suffisamment grands lorsque vous travaillez avec des entiers de taille fixe. La syntaxe correcte varie en fonction du langage de programmation réel que vous utilisez, mais quelque chose dans ce cas résoudra le problème: m ← (l + r) >>> 1
, où >>>
Est l'opérateur de décalage vers la droite non signé. En savoir plus sur le problème dans ici .