2010-09-27 14 views
0

Si on me donne un certain nombre de nombres (que je stocke dans un arbre de recherche binaire équilibré pour la facilité), alors je veux répondre à une requête qui me demande Pour savoir quel est le plus petit nombre entre [A, B], quel serait un algorithme rapide pour effectuer cette tâche? Techniquement, je pourrais traverser l'arbre de la racine en cherchant A (ou un nombre immédiatement supérieur à celui si A n'est pas présent), que revenir en arrière en cherchant B (ou un nombre plus petit que B), et en faisant cela je pourrais garde un compteur pour moi, pour déterminer quand je serais au numéro it. Mais cela ne me semble pas optimal. Puis-je effectuer cette opération sur O (log n), hauteur de l'arbre que j'utilise pour stocker l'ensemble de nombres universel?Meilleure façon de sélectionner le plus petit nombre d'une séquence de nombres délimitée

Merci

+0

Je pense que je reçois quelque chose de mal ici, mais ne pouvez-vous pas simplement rechercher la valeur immédiatement supérieure à A, puis juste traverser 'i'-1 fois? C'est un arbre de recherche binaire, donc c'est trié, n'est-ce pas? J'imagine votre arbre comme ceci: http://en.wikipedia.org/wiki/File:AVLtreef.svg - et dans cet exemple, f.e. chercher le 4ème plus petit nombre dans [15,60] conduirait au résultat 50, non? – schnaader

+1

@schnaader Je suppose, il veut chercher 50000-ème nombre dans un arbre de taille 100000 :) Mais votre chemin est certainement optimal si _k_ est petit. –

+0

@Nikita: Merci pour la clarification. – schnaader

Répondre

5

Vous ne pouvez certainement le faire, si vous pouvez conserver certaines informations dans les noeuds. Pour faire la traversée O(logn), nous avons besoin que chaque nœud sache combien de nœuds son sous-arbre a. (Vous pouvez conserver ces informations et que vous avez encore ajouter à/enlever de l'arbre en O (log (n)))

def search(currentNode, k) 
    if k == 0 then 
     return currentNode 
    else if currentNode.rightBranchSize >= k then 
     // we remove 1 from k because currentNode isn't considered anymore 
     return search(currentNode.right, k - 1) 
    else 
     // we decrease k because currentNode and its whole right subtree aren't considered anymore 
     return search(currentNode.parent, k - currentNode.rightBranchSize - 1) 
    end 
end 

Le code devrait être assez explicite.
Nous commençons par currentNode étant le premier noeud avec le numéro >= A et recherchons l'élément k (th est 0).

  1. Comme schnaader dans son commentaire, il serait plus facile de l'arbre traverse si k est petit.
  2. La plupart des librairies étendues (comme STL) ne vous permettent pas de traverser l'arborescence de cette façon (elles ne fournissent aucun type de struct Node avec des pointeurs vers les sous-arborescences gauche et droite). Donc, bien que l'algorithme soit simple, sa mise en œuvre pourrait être difficile.
  3. Il suffit de peu de modifications pour considérer B de votre question.
+0

Salut Nikkita, merci pour la réponse. J'avais en fait l'algorithme que vous avez décrit. Mais ma pensée était que, si je lance d'abord une recherche pour trouver A (et déterminer mon currentNode, en utilisant votre nomenclature), puis je reviens sur mon arbre, en vérifiant le nombre d'éléments sur les sous-arbres pendant la recherche du nombre ith dans l'intervalle entre A et B (ou pour déterminer qu'il n'existe pas), ne devrais-je pas effectuer quelques opérations de plus, et ce faisant, ma complexité serait supérieure à O (log n), puisque c'était le moment a pris pour moi de chercher A? Merci beaucoup;) – AlexTex

+0

@AlexTex Trouver le premier nombre> = A prend exactement le temps O (logn) dans l'arbre binaire. L'algorithme que j'ai décrit prend également le temps O (logn). Et O (logn + logn) == O (logn), donc l'algorithme entier prend le temps O (logn).(en supposant que vous avez déjà calculé la taille des sous-arbres) –

+0

@Nikkita Rybak Bon point;) – AlexTex