web-dev-qa-db-fra.com

Nième élément le plus grand dans un arbre de recherche binaire

Comment trouver le Nème plus grand noeud d'un BST?

Est-ce que je garde une variable de comptage lors de la traversée dans l'ordre d'une BST? Renvoie l'élément lorsque le compte = N ???

16
Jony

Voir ma réponse ici . Vous pouvez le faire dans O(log n) en moyenne où n = nombre de nœuds. Le cas le plus défavorable reste toujours O(n) SI l'arbre n'est pas équilibré (toujours O(log n) s'il est équilibré). Dans l'ordre, la traversée est toujours O(n) cependant.

8
IVlad

L'idée est très simple: parcourez l'arbre dans l'ordre décroissant des valeurs de chaque nœud. Lorsque vous atteignez le nœud Nth, imprimez cette valeur de nœud. Voici le code récursif.

void printNthNode(Node* root, int N)
{
   if(root == NULL)
       return;

   static int index = 0; //These will initialize to zero only once as its static

   //For every Node go to the right of that node first.
   printNthNode(root->right, N);


   //Right has returned and now current node will be greatest
   if(++index == N)
   {
    printf("%d\n", root->data);
    return;
   }

   //And at last go to the left
   printNthNode(root->left, N);
}

Modifier - Selon les commentaires ci-dessous, il semblerait que ce soit une fonction d'appel unique due à la variable locale statique. Ceci peut être résolu en passant l'objet wrapper pour index comme suit:

    class WrapIndex {
         public: int index;
    };

et la signature de la méthode changerait à

void printNthNode(Node* root, int N, WrapIndex wrapInd)

Maintenant, nous n’avons pas besoin d’une variable statique locale; utilisez plutôt index de l'objet wrapper. L'appel ressemblerait à

WrapIndex wrapInd = new WrapIndex();
wrapInd.index=0;
printNthNode(root,7,wrapInd);

wrapInd.index=0;
printNthNode(root,2,wrapInd);
21
Vallabh Patade

Astuce: utilisez inorder traversal de l’arbre. Il peut imprimer les éléments dans un ordre trié afin que vous puissiez trouver le Nème élément le plus volumineux. Gardez un compteur pendant que vous "marchez", en augmentant chaque fois que vous "visitez" un nœud. 

Éditer : Bien que la réponse d'IVlad soit effectivement plus rapide, elle nécessite de conserver des informations supplémentaires dans les nœuds. Cette réponse ne fonctionne pas mais c'est O(n). En soulignant que c'est un compromis dont vous devez être conscient.

10
Eli Bendersky
  • Conservez la taille du sous-arbre à chaque noeud (root.size quelque chose comme ça). Par exemple, {2,3,1} est un arbre binaire avec la racine 2, la taille du noeud (2) est égale à 3, la taille du noeud (1) est égale à 1 et la taille du noeud (2) est égale à 1. 

  • si vous voulez trouver le 4 ème élément larget dans l’arbre avec une taille de nœud racine 23, pensez à son rang

  • le rang maximum d'éléments est 23, car la taille du nœud racine est 23. Le rang rang 4 des éléments les plus importants est 23-4 + 1 = 20

  • nous devons donc trouver le 20ème élément de rang dans l'arbre donné

  • déclarer initialement un rang = 0 drapeau à zéro

  • en partant du noeud racine, trouvez son rang (rang + taille de l'enfant gauche + 1), par exemple, sa taille est de 16 puis le rang de l'élément racine est de 17 (rang + taille de son enfant +1)

  • donc nous devons rechercher l'élément avec le rang 20 alors évidemment nous devons traverser jusqu'à son enfant droit

  • traversez vers le bon enfant et sur la base de la formule ci-dessus, trouvez le bon rang pour l'enfant (sur la base de la formule ci-dessus, remarque: la valeur du drapeau de rang est maintenant égale à 17), indiquez si vous souhaitez aller à droite ou à gauche selon le rang 

  • répétez ce processus jusqu'à ce que nous ayons trouvé un rang == 20
0
pashaplus

Ce morceau de code provient de mon affectation et l'une des conditions était de ne pas utiliser les tableaux Afin de rendre le code plus compact et lisible, vous pouvez utiliser StringName.split ("|"). Comme la méthode est récursive, j'utilise le stringBuilder Qui a la structure suivante: "counter | orderOfElementToFind | dataInrequiredNode"

protected StringBuilder t(StringBuilder s)
{
    if (lc != null) 
    {
        lc.t(s);
}


if((s.toString().charAt(s.toString().length() - 1)) == '|')
{
        String str = s.toString();
    s.delete(0, s.length());

        int counter = 0, k = 0;


        String strTemp = "", newStrBuilContent = "";

        for (int i = 0, c = 0 ; i < str.length(); ++i)
        {
            if (c == 0)
            {
            if (str.charAt(i) != '|')
    {
        strTemp += str.charAt(i); 
    }
    else
    {
        counter = Integer.parseInt(strTemp);
        ++c;

        strTemp = "";
    }
            }
    else
    {

            if (str.charAt(i) != '|')
        {
            strTemp += str.charAt(i); 
            }
        else
        {
                k = Integer.parseInt(strTemp);
        }

    }

    counter ++;

            newStrBuilContent = (counter + "|" + k + "|");
    s.append(newStrBuilContent);
    if (counter == k)
    {
        double ldata = this.getData();
        s.append(ldata);

    }

}

if (rc != null) 
{
    rc.t(s);
} 

    return s;

}

et l'appel de méthode:

// the value of counter ad the beginning is 0 and data 
// segment is missing
String s = ("0|" + order +"|");
StringBuilder strBldr = new StringBuilder(s); 
String content = sTree.t(strBldr).toString();

s = "";

for (int i = 0, c = 0; i < content.length(); ++i)
{           
    if (c < 2)
{
    if (content.charAt(i) == '|')
    {  
        ++c;
        }
    }
else
{
    s += content.charAt(i);
}
}
    `
0
Alex

Utilisez un ordre inverse inversé. C’est-à-dire aller à l’enfant droit en premier au lieu de l’enfant gauche . De manière récursive, on peut l’obtenir de la manière suivante:.

reverseInorder(root){
 if(root!=null){
reverseInorder(root->rightChild);
self
reverseInorder(root->leftChild);
}
}

Solution en Java 

    package datastructure.binaryTree;

import datastructure.nodes.BinaryTreeNode;


public class NthElementFromEnd {
    private BinaryTree tree=null;
    int currCount=0;
    public NthElementFromEnd(int[] dataArray) {
        this.tree=new BinaryTree(dataArray);

    }
    private void getElementFromEnd(int n){
        getElementFromEnd(this.tree.getRoot(),n);
    }
    private void getElementFromEnd(BinaryTreeNode node,int n){
        if(node!=null){
            if(currCount<n)
            getElementFromEnd(node.getRightChild(),n);
            currCount++;

            if(currCount==n)
            {
                System.out.print(" "+node.getData());
                return;
            }
            if(currCount<n)
            getElementFromEnd(node.getLeftChild(),n);
        }
    }

    public static void main(String args[]){
        int data[]={1,2,3,4,5,6,7,8,9};
        int n=2;
        new NthElementFromEnd(data).getElementFromEnd(n);
    }
}
0
frictionlesspulley
// C++ program to find k'th largest element in BST
#include<iostream>
using namespace std;

struct Node
{
    int key;
    Node *left, *right;
};

// A utility function to create a new BST node
Node *newNode(int item)
{
    Node *temp = new Node;
    temp->key = item;
    temp->left = temp->right = NULL;
    return temp;
}

// A function to find k'th largest element in a given tree.
void kthLargestUtil(Node *root, int k, int &c)
{
    // Base cases, the second condition is important to
    // avoid unnecessary recursive calls
    if (root == NULL || c >= k)
        return;

    // Follow reverse inorder traversal so that the
    // largest element is visited first
    kthLargestUtil(root->right, k, c);

    // Increment count of visited nodes
    c++;

    // If c becomes k now, then this is the k'th largest 
    if (c == k)
    {
        cout << "K'th largest element is "
             << root->key << endl;
        return;
    }

    // Recur for left subtree
    kthLargestUtil(root->left, k, c);
}

// Function to find k'th largest element
void kthLargest(Node *root, int k)
{
    // Initialize count of nodes visited as 0
    int c = 0;

    // Note that c is passed by reference
    kthLargestUtil(root, k, c);
}

/* A utility function to insert a new node with given key in BST */
Node* insert(Node* node, int key)
{
    /* If the tree is empty, return a new node */
    if (node == NULL) return newNode(key);

    /* Otherwise, recur down the tree */
    if (key < node->key)
        node->left  = insert(node->left, key);
    else if (key > node->key)
        node->right = insert(node->right, key);

    /* return the (unchanged) node pointer */
    return node;
}

// Driver Program to test above functions
int main()
{
    /* Let us create following BST
              50
           /     \
          30      70
         /  \    /  \
       20   40  60   80 */
    Node *root = NULL;
    root = insert(root, 50);
    insert(root, 30);
    insert(root, 20);
    insert(root, 40);
    insert(root, 70);
    insert(root, 60);
    insert(root, 80);

    int c = 0;
    for (int k=1; k<=7; k++)
        kthLargest(root, k);

    return 0;
}
0
sankar

Je le ferais en allant de l'arbre du plus grand au plus petit élément et en retournant une valeur lorsque la position demandée est atteinte J'ai mis en œuvre une tâche similaire pour la deuxième plus grande valeur. La valeur 2 est codée en dur, mais est-il facile de changer avec un paramètre supplémentaire :)

void BTree::findSecondLargestValueUtil(Node* r, int &c, int &v)
{
    if(r->right) {
        this->findSecondLargestValueUtil(r->right, c, v);
    }

    c++;

    if(c==2) {
        v = r->value;
        return;
    }

    if(r->left) {
        this->findSecondLargestValueUtil(r->left, c, v);
    }
}


int BTree::findSecondLargestValue()
{
    int c = 0;
    int v = -1;

    this->findSecondLargestValueUtil(this->root, c, v);

    return v;
}
0
Oleksandr Knyga
int nLargeBST(node *root, int N) {
    if (!root || N < 0) {
        return -1;
    }
    nLargeBST(root->left, N);
    --N;
    if(N == 0) {
        return root->val;
    }
    nLargeBST(root->right, N);
}
0
user1148976