Najít vyměnil uzly v BST

hlasů
6

Snažím se napsat program, který může rozpoznat a vytisknout dva uzly v BST, které byly zaměněny.

Ve stromu tři úrovně, dosáhl jsem blízko k řešení pomocí tohoto přístupu.

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

ale výše uvedený přístup selhal, když jsem se snažil otestovat čtyři úrovně stromu.

             20

      15            30

   10    17       25     33

9  16  12  18  22  26  31  34

Být v pravém podstromu kořene 15 na 12 je ještě větší (narušení).

Být v levém podstromu kořenový uzel 15 na 16 je ještě větší (porušení).

Takže, 16, 12 jsou vyměnili prvky ve výše uvedeném BST. Jak najdu je prostřednictvím programu?

Položena 31/08/2011 v 17:30
zdroj uživatelem
V jiných jazycích...                            


3 odpovědí

hlasů
0

Myslím, že váš getMin et getMax pracuje witht hypotézami, že strom je BST, tak

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

(Nebo ekvivalent kód se smyčkou). Pokud ano, váš kód zkoumá nanejvýš tři hodnoty na stromě. I v případě, getMax a getMin projet celý strom, aby si skutečnou max / min, měli byste ještě založit svůj test na pouhé dvě srovnání. Chcete-li zkontrolovat, zda váš strom uspokojí vlastnost BST, je zřejmé, že budete muset prozkoumat všechny hodnoty. Jeho dost srovnat každý uzel s jeho rodiči.

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
}

Edit : to bylo v pořádku, viz komentář. Věřím, že tohle je v pořádku.

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
}

Volání z kořene s null mezích

Odpovězeno 31/08/2011 v 18:03
zdroj uživatelem

hlasů
8

Jeden způsob, jak přemýšlet o tomto problému je použít k tomu, že nezbytného chůze od stromu bude vyrábět všechny prvky v seřazeném pořadí. Pokud můžete odhalit odchylky od seřazeném pořadí při procházce, můžete se pokusit najít tyto dva prvky, které jsou na špatném místě.

Podívejme se, jak to udělat jednoduchý seřazeném poli, poté bude používat náš algoritmus vybudovat něco, co funguje na stromech. Intuitivně, pokud bychom začít s tříděným pole a poté vymění dva (non-stejné!) Elementů, skončíme s nějakým počtem prvků v matici bytí mimo mísu. Například, vzhledem k matici

1 2 3 4 5

Budeme-li vyměnit 2 a 4, skončíme s tímto polem:

1 4 3 2 5

Jak by zjistíme, že 2 a 4 byly tady vyměnil? Tak, protože 4 je větší ze dvou prvků, a byl vyměněn směrem dolů, to by mělo být větší než oba prvky kolem něj. Podobně, protože 2 byl vyměněn se, že by mělo být menší, než oba prvky kolem něj. Z toho můžeme vyvodit, že 2 a 4 byly zaměněny.

Nicméně, to nemusí vždy fungovat správně. Předpokládejme například, že máme vyměnit 1 a 4:

4 2 3 1 5

Zde, jak 2 a 1 jsou menší než jejich sousedními prvky, a to jak 4 a 3 jsou větší než jejich. Z toho můžeme říci, že dva z těchto čtyř nějak byly zaměněny, ale to není jasné, které z nich bychom měli výměnu. Nicméně, vezmeme-li v největší a nejmenší z těchto hodnot (1 až 4, v uvedeném pořadí), jsme se nakonec dostat pár, který byl prohozené.

Obecněji řečeno, najít prvky, které byly zaměněny v pořadí, chcete najít

  • Největší lokální maximum v poli.
  • Nejmenší lokální minimum v poli.

Tyto dva prvky jsou na svém místě a měl by být vyměněn.

Nyní se pojďme přemýšlet o tom, jak aplikovat na stromech. Vzhledem k tomu, jako nezbytného chůze stromu bude produkovat seřazené sekvenci s dvěma prvky mimo provoz, jednou z možností by bylo jít na strom, záznam nezbytného posloupnost prvků jsme našli, pak pomocí výše uvedeného algoritmu. Vezměme si například původní BST:

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

Kdybychom linearizovat to do pole, dostaneme

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

Všimněte si, že 16 je větší než jeho obklopující prvky, a to 12, je menší než jeho. To nám říká, že hned 12 a 16 byly zaměněny.

Jednoduchý algoritmus pro řešení tohoto problému, a proto by bylo udělat nezbytného chůze stromu jej linearizovat do sekvence jako vectorOr deque, pak skenovat tuto sekvenci najít největší lokální maximum, a naopak nejmenší lokální minimum. To by bylo v O (n), za použití O (n) prostor. Složitější, ale více prostorově nenáročný algoritmus by bylo jen sledovat tří uzlů najednou - aktuální uzel, jeho předchůdce, a jeho nástupce - což snižuje využití paměti O (1).

Snad to pomůže!

Odpovězeno 31/08/2011 v 21:22
zdroj uživatelem

hlasů
0

strom traversal provádí templatetypedef funguje, pokud jste si jisti, že je jen jedna výměna. Jinak bych navrhnout řešení na základě vašeho původního kódu:

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

Je pomalejší, ale vytiskne všechny swapy identifikuje. Může být změněn vytisknout všechna porušení (např if (max_left> stromově> data) print narušení). Můžete zlepšit výkon, pokud můžete přidat dvě pole do TreeNode s max a min Precomputed pro tento podstrom.

Odpovězeno 01/09/2011 v 08:43
zdroj uživatelem

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