Trouver des nœuds dans un BST permutées

voix
6

Je suis en train d'écrire un programme qui permet de détecter et imprimer deux noeuds de BST qui ont été échangées contre.

Dans un arbre à trois niveaux, je suis arrivé près de la solution en utilisant cette approche.

If (!AllSubTreeAreValid())
{
//Nodes swapped on same side of main root node
}
else
{
  int max = getMax(root->left);
  int min = getMin(root->right);
  if(max > root->data || min < root->data )
  {
     //Nodes swapped on different sides of main root node
     //Print max and min values

  }
else 
{
 //No node swappped
}
}

//Helper functions
int GetMaxEle(TreeNode* tree)
{
    while(tree->right!=NULL)
    {
        tree=tree->right;
    }
    return tree->info;
}

int GetMinEle(TreeNode* tree)
{
    while(tree->left!=NULL)
    {
        tree=tree->left;
    }
    return tree->info;
}

mais l'approche ci-dessus a échoué quand j'ai essayé de tester avec quatre arbres de niveau.

             20

      15            30

   10    17       25     33

9  16  12  18  22  26  31  34

Être en sous-arbre droit de nœud racine 15, 12 est encore plus (violation).

Être en sous-arbre gauche du noeud racine 15, 16 est encore plus (violation).

Donc, 16, 12 sont les éléments ci-dessus dans permutées BST. Comment puis-je les trouver à travers le programme?

Créé 31/08/2011 à 17:30
source utilisateur
Dans d'autres langues...                            


3 réponses

voix
0

Je suppose que votre getMin et getMax fonctionne witht les hypothèses que l'arbre est un BST, donc

T getMax(tree) {
  return tree -> right == null 
    ? tree -> value 
    : getMax(tree -> right);
}

(Ou le code équivalent avec une boucle). Dans ce cas, votre code examine au plus trois valeurs dans l'arborescence. Même si getMax et getMin traversèrent l'arbre complet pour obtenir le maximum / min réelle, vous baser encore votre test sur seulement deux comparaisons. Si vous voulez vérifier que votre arbre satisfaire la propriété BST, il est évident que vous devez examiner toutes les valeurs. Son suffit de comparer chaque noeud avec son parent.

void CheckIsBst(Tree *tree) {
  if (tree -> left != null) {
    if (tree -> left -> value > tree -> value) {
      // print violation
    }
    CheckIsBst(tree -> left);   
  }
  // same with -> right, reversing < to > in the test
}

Modifier : qui a eu tort, voir le commentaire. Je crois que celui - ci est ok.

void checkIsBst(Tree *Tree, Tree *lowerBound, Tree *upperBound) {
  if(lowerBound!= null && lowerBound -> value > tree -> Value) {
    //violation
  }
  // same for upper bound, check with <
  if (tree -> left != null) {
    if (tree -> left -> value > tree -> value) {
      // print violation
     }
     CheckIsBst(tree -> left, lowerBound, tree);   
  }
  // same for right, reversing comparison 
  // setting lowerBound to tree instead of upperBound
}

Appel de la racine avec des limites null

Créé 31/08/2011 à 18:03
source utilisateur

voix
8

Une façon de penser à ce problème est d'utiliser le fait qu'une promenade envue de l'arbre produira tous les éléments dans l'ordre. Si vous pouvez détecter les écarts de l'ordre de tri cours de cette promenade, vous pouvez essayer de localiser les deux éléments qui sont au mauvais endroit.

Voyons voir comment faire cela pour un simple tableau trié, puis utilisera notre algorithme pour construire quelque chose qui fonctionne sur les arbres. Intuitivement, si nous commençons avec un tableau trié puis échanger deux éléments (non égaux!), Nous finirons avec un certain nombre d'éléments du tableau étant hors de propos. Par exemple, étant donné le tableau

1 2 3 4 5

Si nous échangeons des 2 et 4, nous nous retrouvons avec ce tableau:

1 4 3 2 5

Comment pourrions-nous détecter 2 et 4 ont été échangés ici? Eh bien, puisque 4 est la plus grande des deux éléments et a été échangé vers le bas, il devrait être supérieur à la fois des éléments autour de lui. De même, parce que 2 a été échangé, il devrait être plus petit que les deux éléments autour d'elle. De là, nous pourrions conclure que 2 et 4 ont été permutées.

Cependant, cela ne fonctionne pas toujours correctement. Par exemple, supposons que nous échangeons 1 et 4:

4 2 3 1 5

Ici, à la fois 2 et 1 sont plus petits que leurs éléments voisins, et les deux 4 et 3 sont plus grandes que les leurs. De cela, nous pouvons dire que deux de ces quatre ont été en quelque sorte troqué, mais on ne sait pas quels sont ceux que nous devrions échanger. Cependant, si l'on prend la plus grande et la plus petite de ces valeurs (1 et 4, respectivement), on finit par obtenir la paire qui a été échangé.

De manière plus générale, de trouver les éléments qui ont été échangés dans la séquence, vous voulez trouver

  • Le plus grand maximum local dans le tableau.
  • Le minimum local le plus petit dans le tableau.

Ces deux éléments sont hors de place et doivent être permutés.

Maintenant, nous allons réfléchir à la façon de l'appliquer à des arbres. Depuis une promenade infixe de l'arbre produira la séquence triée avec les deux éléments sur commande, une option serait de marcher l'arbre, l'enregistrement de la séquence envue d'éléments que nous avons trouvé, en utilisant l'algorithme ci-dessus. Par exemple, pensez à votre BST d'origine:

              20
         /         \
      15             30
     /   \         /   \ 
   10    17      25     33
  / |   /  \    /  \    |  \
9  16  12  18  22  26  31  34

Si nous linéarisons cela dans un tableau, nous obtenons

9 10 16 15 12 17 18 20 22 25 26 30 31 33 34

Notez que 16 est plus grande que ses éléments qui l'entourent et qui 12 est inférieure à sa. Cela nous dit immédiatement que 12 et 16 ont été permutées.

Un algorithme simple pour résoudre ce problème, donc, serait de faire une promenade envue de l'arbre à linéariser dans une séquence comme une vectorou deque, puis à analyser cette séquence pour trouver le plus grand maximum local et le minimum local plus petit. Cela irait dans O (n), en utilisant l' espace O (n). Un plus délicat mais plus algorithme efficace espace serait seulement garder une trace de trois nœuds à un moment - le nœud actuel, son prédécesseur et son successeur - ce qui réduit l'utilisation de la mémoire à O (1).

J'espère que cela t'aides!

Créé 31/08/2011 à 21:22
source utilisateur

voix
0

l'arbre traversal fait par templatetypedef fonctionne si vous êtes sûr qu'il n'y a qu'un seul échange. Sinon , je vous propose une solution en fonction de votre code initial:

int GetMax(TreeNode* tree) {
    int max_right, max_left, ret;

    ret = tree->data;
    if (tree->left != NULL) {
        max_left = GetMax(tree->left);
        if (max_left > ret)
            ret = max_left;
    }
    if (tree->right != NULL) {
        max_right = GetMax(tree->right);
        if (max_right > ret)
            ret = max_right;
    }

    return ret;
}

int GetMin(TreeNode* tree) {
    int min_right, min_left, ret;

    ret = tree->data;
    if (tree->left != NULL) {
        min_left = GetMin(tree->left);
        if (min_left < ret)
            ret = min_left;
    }
    if (tree->right != NULL) {
        min_right = GetMin(tree->right);
        if (min_right < ret)
            ret = min_right;
    }

    return ret;
}

void print_violations(TreeNode* tree) {
    if ((tree->left != NULL) && (tree->right != NULL)) {
        int max_left = GetMax(tree->left);
        int min_right = GetMin(tree->right);
        if (max_left > tree->data && min_right < tree->data) {
            printf("Need to swap %d with %d\n", max_left, min_right);
        }
    }
    if (tree->left != NULL)
        print_violations(tree->left);
    if (tree->right != NULL)
        print_violations(tree->right);
}

Il est plus lent, mais il imprime tous les swaps qu'elle identifie. Peut être changé d'imprimer toutes les violations (par exemple si (données max_left> arborescente>) violation d'impression). Vous pouvez améliorer les performances si vous pouvez ajouter deux champs à la TreeNode avec le max et min précalculées pour cette sous-arbre.

Créé 01/09/2011 à 08:43
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more