J'ai besoin de trouver le kème plus petit élément dans l'arbre de recherche binaire sans utiliser de variable statique / globale. Comment y parvenir efficacement? La solution que j'ai dans mon esprit est de faire l'opération en O (n), le pire des cas puisque je prévois de faire une traversée en ordre de l'arbre entier. Mais au fond, je sens que je n'utilise pas la propriété BST ici. Ma solution hypothétique est-elle correcte ou existe-t-il une meilleure solution disponible?
112
Réponses:
Voici juste un aperçu de l'idée:
Dans un BST, le sous-arbre gauche du nœud
T
contient uniquement des éléments plus petits que la valeur stockée dansT
. Sik
est inférieur au nombre d'éléments dans le sous-arbre de gauche, lek
e plus petit élément doit appartenir au sous-arbre de gauche. Sinon, sik
est plus grand, alors lek
e plus petit élément se trouve dans le sous-arbre de droite.Nous pouvons augmenter le BST pour que chaque nœud qu'il contient stocke le nombre d'éléments dans son sous-arbre gauche (supposons que le sous-arbre gauche d'un nœud donné inclut ce nœud). Avec cette information, il est simple de parcourir l'arborescence en demandant à plusieurs reprises le nombre d'éléments dans le sous-arbre de gauche, pour décider s'il faut récurer dans le sous-arbre de gauche ou de droite.
Maintenant, supposons que nous soyons au nœud T:
T
.k
e plus petit. Ainsi, nous réduisons le problème à la recherche duk - num_elements(left subtree of T)
plus petit élément du bon sous-arbre.k
e plus petit se trouve quelque part dans le sous-arbre gauche, nous réduisons donc le problème à trouver lek
e plus petit élément dans le sous-arbre gauche.Analyse de complexité:
Cela prend du
O(depth of node)
temps, ce qui estO(log n)
dans le pire des cas sur un BST équilibré, ouO(log n)
en moyenne pour un BST aléatoire.Un BST nécessite un
O(n)
stockage, et il en faut un autreO(n)
pour stocker les informations sur le nombre d'éléments. Toutes les opérations BST prennent duO(depth of node)
temps, et il fautO(depth of node)
plus de temps pour conserver les informations de «nombre d'éléments» pour l'insertion, la suppression ou la rotation des nœuds. Par conséquent, le stockage des informations sur le nombre d'éléments dans le sous-arbre de gauche conserve la complexité spatiale et temporelle d'un BST.la source
Une solution plus simple serait de faire une traversée dans l'ordre et de garder une trace de l'élément actuellement à imprimer (sans l'imprimer). Lorsque nous atteignons k, imprimez l'élément et sautez le reste de la traversée de l'arbre.
la source
c'est mon implémentation en C # basée sur l'algorithme ci-dessus, je pensais juste que je le publierais pour que les gens puissent mieux comprendre que cela fonctionne pour moi
merci IVlad
la source
Une solution plus simple serait de faire une traversée dans l'ordre et de garder une trace de l'élément actuellement à imprimer avec un compteur k. Lorsque nous atteignons k, imprimez l'élément. Le runtime est O (n). Rappelez-vous que le type de retour de fonction ne peut pas être void, il doit renvoyer sa valeur mise à jour de k après chaque appel récursif. Une meilleure solution à cela serait un BST augmenté avec une valeur de position triée à chaque nœud.
la source
// ajoute une version java sans récursivité
la source
Vous pouvez utiliser la traversée itérative dans l'ordre: http://en.wikipedia.org/wiki/Tree_traversal#Iterative_Traversal avec une simple vérification du kème élément après avoir sorti un nœud de la pile.
la source
Étant donné juste un arbre de recherche binaire simple, tout ce que vous pouvez faire est de commencer par le plus petit et de traverser vers le haut pour trouver le bon nœud.
Si vous comptez faire cela très souvent, vous pouvez ajouter un attribut à chaque nœud indiquant le nombre de nœuds dans sa sous-arborescence de gauche. En utilisant cela, vous pouvez descendre l'arborescence directement vers le nœud correct.
la source
Marche dans l'ordre récursive avec un compteur
L'idée est similaire à la solution @prasadvk, mais elle présente quelques lacunes (voir les notes ci-dessous), je publie donc ceci comme une réponse séparée.
Notes (et différences avec la solution de @ prasadvk):
if( counter == k )
le test est requis à trois endroits: (a) après le sous-arbre de gauche, (b) après la racine et (c) après le sous-arbre de droite. Ceci permet de garantir que le kème élément est détecté pour tous les emplacements , c'est-à-dire quel que soit le sous-arbre dans lequel il se trouve.if( result == -1 )
test requis pour s'assurer que seul l'élément de résultat est imprimé , sinon tous les éléments à partir du kème plus petit jusqu'à la racine sont imprimés.la source
O(k + d)
, oùd
est la profondeur maximale de l'arbre. Par conséquent, il utilise une variable globalecounter
mais c'est illégal pour cette question.Pour un arbre de recherche non équilibré, il faut O (n) .
Pour un arbre de recherche équilibré , il prend O (k + log n) dans le pire des cas mais juste O (k) au sens Amorti .
Avoir et gérer l'entier supplémentaire pour chaque nœud: la taille du sous-arbre donne une complexité temporelle O (log n) . Un tel arbre de recherche équilibré est généralement appelé RankTree.
En général, il existe des solutions (non basées sur l'arbre).
Cordialement.
la source
Cela fonctionne bien: status: est le tableau qui contient si l'élément est trouvé. k: est le kième élément à trouver. count: garde la trace du nombre de nœuds traversés pendant la traversée de l'arborescence.
la source
Bien que ce ne soit certainement pas la solution optimale au problème, c'est une autre solution potentielle que je pensais que certaines personnes pourraient trouver intéressante:
la source
Signature:
appeler comme:
définition:
la source
Et bien voici mes 2 centimes ...
la source
C'est ce que j'ai pensé et ça marche. Il fonctionnera en o (log n)
la source
Eh bien, nous pouvons simplement utiliser la traversée dans l'ordre et pousser l'élément visité sur une pile. pop k nombre de fois, pour obtenir la réponse.
on peut aussi s'arrêter après k éléments
la source
Solution pour un cas BST complet: -
la source
Le noyau Linux a une excellente structure de données arborescente rouge-noire augmentée qui prend en charge les opérations basées sur les rangs dans O (log n) dans linux / lib / rbtree.c.
Un port Java très grossier peut également être trouvé à http://code.google.com/p/refolding/source/browse/trunk/core/src/main/java/it/unibo/refolding/alg/RbTree.java , avec RbRoot.java et RbNode.java. Le nième élément peut être obtenu en appelant RbNode.nth (nœud RbNode, int n), en passant à la racine de l'arbre.
la source
Voici une version concise en C # qui renvoie le k-ième élément le plus petit, mais nécessite de passer k comme argument ref (c'est la même approche que @prasadvk):
C'est O (log n) pour trouver le plus petit nœud, puis O (k) pour traverser jusqu'au k-ème nœud, donc c'est O (k + log n).
la source
http://www.geeksforgeeks.org/archives/10379
c'est la réponse exacte à cette question: -
1. utilisation de la traversée en ordre sur le temps O (n) 2. utilisation de l'arbre augmenté en temps k + log n
la source
Je n'ai pas pu trouver un meilleur algorithme ... j'ai donc décidé d'en écrire un :) Corrigez-moi si c'est faux.
}
la source
Voici le code java,
max (Node root, int k) - pour trouver kth plus grand
min (Node root, int k) - pour trouver le kth le plus petit
la source
cela fonctionnerait aussi. appelez simplement la fonction avec maxNode dans l'arborescence
def k_largest (self, node, k): if k <0: return None
if k == 0: return node else: k - = 1 return self.k_largest (self.predecessor (node), k)
la source
Je pense que c'est mieux que la réponse acceptée car il n'est pas nécessaire de modifier le nœud d'arbre d'origine pour stocker le nombre de ses nœuds enfants.
Nous avons juste besoin d'utiliser le parcours dans l'ordre pour compter le plus petit nœud de gauche à droite, arrêtez la recherche une fois que le nombre est égal à K.
la source
La meilleure approche existe déjà, mais j'aimerais ajouter un code simple pour cela
}
la source
Utilisation de la classe Result auxiliaire pour suivre si le nœud est trouvé et le k courant.
la source
Complexité temporelle de la solution Python: O (n) Complexité spatiale: O (1)
L'idée est d'utiliser Morris Inorder Traversal
la source
J'ai écrit une fonction soignée pour calculer le kième élément le plus petit. J'utilise la traversée dans l'ordre et m'arrête quand il atteint le kème plus petit élément.
la source
la source
la source
}
la source