Encuentra nodos intercambian en un BST

votos
6

Estoy tratando de escribir un programa que puede detectar e imprimir dos nodos en BST que han sido intercambiadas.

En un árbol de tres niveles, llegué cerca de la solución utilizando este enfoque.

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;
}

pero el enfoque anterior fracasó cuando intentó probar con cuatro árbol de nivel.

             20

      15            30

   10    17       25     33

9  16  12  18  22  26  31  34

Estar en subárbol derecho del nodo raíz 15, 12 es aún mayor (violación).

Estar en subárbol izquierdo del nodo raíz 15, 16 es aún mayor (violación).

Así, 16, 12 son los elementos intercambiados en el BST anteriormente. ¿Cómo encuentro a través del programa?

Publicado el 31/08/2011 a las 17:30
fuente por usuario
En otros idiomas...                            


3 respuestas

votos
0

Supongo que tu getMin et getMax funciona comunicaba con la hipótesis de que el árbol es un BST, por lo

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

(O el código equivalente con un bucle). Si es así, el código examina como máximo tres valores en el árbol. Incluso si getMax y getMin atravesaron el árbol por completo para obtener el real max / min, a pesar de ello la base de su prueba en tan sólo dos comparaciones. Si desea comprobar que su árbol de satisfacer la propiedad BST, es obvio que hay que examinar todos los valores. Su suficiente para comparar cada nodo con su matriz.

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
}

Editar : lo que estaba mal, ver comentario. Creo que éste es aceptable.

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
}

Llamar desde la raíz con los límites nulos

Respondida el 31/08/2011 a las 18:03
fuente por usuario

votos
8

Una manera de pensar acerca de este problema es utilizar el hecho de que un paseo a finde del árbol producirá todos los elementos en el orden establecido. Si se puede detectar desviaciones de la forma ordenada durante este paseo, se puede tratar de localizar a los dos elementos que están en el lugar equivocado.

Vamos a ver cómo hacer esto por una simple matriz ordenada inicialmente, y luego utilizar nuestro algoritmo para construir algo que funciona en los árboles. Intuitivamente, si partimos de una matriz ordenada y luego intercambiar dos (!) No iguales elementos, vamos a terminar con un número de elementos de la matriz de estar fuera de lugar. Por ejemplo, dada la matriz

1 2 3 4 5

Si cambiar 2 y 4, terminamos con esta matriz:

1 4 3 2 5

¿Cómo podemos detectar que 2 y 4 fueron intercambiados aquí? Bueno, ya que 4 es el mayor de los dos elementos y se intercambiados hacia abajo, debe ser mayor que ambos elementos de su alrededor. Del mismo modo, porque 2 se canjearon hacia arriba, que debe ser más pequeño que los dos elementos a su alrededor. A partir de esto, podemos concluir que 2 y 4 fueron intercambiadas.

Sin embargo, esto no siempre funciona correctamente. Por ejemplo, supongamos que cambiamos 1 y 4:

4 2 3 1 5

Aquí, tanto 2 y 1 son más pequeñas que sus elementos vecinos, y ambos 4 y 3 son más grandes que el de ellos. De esto podemos decir que dos de estos cuatro fueron cambiados de alguna manera, pero no es claro cuáles debemos intercambiar. Sin embargo, si tomamos el más grande y el más pequeño de estos valores (1 y 4, respectivamente), terminamos encima de conseguir el par que se va a intercambiar.

De manera más general, para encontrar los elementos que fueron cambiados en la secuencia, que desea buscar

  • El mayor máximo local de la matriz.
  • El mínimo local más pequeño en la matriz.

Estos dos elementos están fuera de lugar y deben ser cambiados.

Ahora, vamos a pensar en cómo aplicar esto a los árboles. Desde un paseo finde del árbol producirá la secuencia ordenada con los dos elementos fuera de servicio, una opción sería la de recorrer el árbol, la grabación de la secuencia finde de elementos que hemos encontrado, a continuación, utilizando el algoritmo anterior. Por ejemplo, considere su BST originales:

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

Si nos linealizar esta en una matriz, obtenemos

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

Observe que 16 es mayor que sus elementos circundantes y que 12 es menor que su. Esto nos dice inmediatamente que el 12 y 16 fueron intercambiadas.

Un algoritmo sencillo para resolver este problema, por lo tanto, sería hacer un paseo a finde del árbol para linealizar en una secuencia como una vectoro deque, a continuación, para analizar esa secuencia para encontrar el mayor máximo local y el mínimo local más pequeño. Esto iría en en tiempo O (n), usando O espacio (n). Un algoritmo eficiente con el espacio más complicado pero más sería solamente un seguimiento de tres nodos a la vez - el nodo actual, su predecesor, y su sucesor - que reduce el uso de memoria a O (1).

¡Espero que esto ayude!

Respondida el 31/08/2011 a las 21:22
fuente por usuario

votos
0

el recorrido del árbol realizado por templatetypedef funciona si está seguro de que sólo hay un intercambio. De lo contrario, sugiero una solución basada en el código inicial:

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);
}

Es más lento, pero imprime todas las permutas que identifica. Puede ser cambiado para imprimir todas las violaciónes (por ejemplo, si (max_left> árbol-> datos) violación de impresión). Puede mejorar el rendimiento si se puede añadir dos campos a la TreeNode con el máximo y el mínimo de cálculo previo para ese sub-árbol.

Respondida el 01/09/2011 a las 08:43
fuente por usuario

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