Keresse cserélték csomópontok BST

szavazat
6

Én próbálok írni egy programot, amely képes felismerni és nyomtatni két csomópont BST, hogy már cserélték.

A három szinten fa, elértem közel a megoldás használja ezt a megközelítést.

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

de a fenti megközelítés nem sikerült, amikor próbáltam tesztelni négy szint fa.

             20

      15            30

   10    17       25     33

9  16  12  18  22  26  31  34

Mivel a gyökér csomópont 15 jogát részfa, 12 még mindig nagyobb (megsértése).

Mivel a gyökér csomópont 15 bal részfa, 16 még mindig nagyobb (megsértése).

Tehát, 16, 12 a cserélt elemek a fenti BST. Hogyan találja őket a programon keresztül?

A kérdést 31/08/2011 17:30
a forrás felhasználó
Más nyelveken...                            


3 válasz

szavazat
0

Azt hiszem, a getMin et getMax működik witht hipotézisek, hogy a fa egy BST, így

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

(Vagy ezzel egyenértékű kódot egy hurok). Ha igen, akkor a kód megvizsgálja legfeljebb három érték a fában. Még ha getMax és getMin áthaladni a teljes fát, hogy a tényleges max / min, akkor még mindig alap a vizsgálat csak két összehasonlítást. Ha azt szeretnénk, hogy ellenőrizze, hogy a fa megfelelnek a BST ingatlan, nyilvánvaló, hogy meg kell vizsgálni az összes értéket. Az elég összehasonlítani az egyes csomópontnak a szülő.

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
}

Szerkesztés : ez volt a baj, lásd megjegyzést. Azt hiszem, ez az egyik 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
}

Hívás gyökér null határokat

Válaszolt 31/08/2011 18:03
a forrás felhasználó

szavazat
8

Az egyik módja annak, hogy gondolni ezt a problémát, hogy az a tény, hogy egy inorder séta a fa fog az összes elemet rendezett sorrendben. Ha képes felismerni eltérések a sorba rendezett során ez a séta, akkor próbálja megkeresni a két elem, amelyek a rossz helyen.

Lássuk, hogyan kell ezt csinálni egy egyszerű rendezett tömbben az első, majd használja a algoritmust építeni valamit, ami működik a fán. Szemléletesen ha elindul egy rendezett tömbben, majd csere két (nem egyenlő!) Elemek, akkor a végén néhány számát a tömb elemeinek, hogy a helyén. Például, mivel a tömb

1 2 3 4 5

Ha cserélni a 2 és 4, akkor a végén ezzel a tömböt:

1 4 3 2 5

Hogyan tudnánk felismerni, hogy a 2. és a 4. helyet cseréltek itt? Nos, mivel a 4. a nagyobb a két elem, és cserélték lefelé, akkor nagyobbnak kell lennie mind az elemek körül. Hasonlóan, mivel 2-t cserélték fel, hogy legyen kisebb, mint mind az elemek körül. Ebből azt a következtetést lehet levonni, hogy a 2. és a 4. helyet cseréltek.

Azonban ez nem mindig működik megfelelően. Tegyük fel például, hogy felcseréljük 1 és 4:

4 2 3 1 5

Itt, a 2 és 1 kisebb, mint a szomszédos elem, és mindkét 4 és 3 nagyobb, mint az övék. Ebből azt lehet mondani, hogy két ilyen négy valahogy kicserélték, de ez nem egyértelmű, melyik kellene felcserélni. Azonban, ha vesszük a legnagyobb és a legkisebb ezen értékek (1, illetve 4), akkor a végén kezd a pár, hogy újra cserélték.

Általánosabban, hogy megtalálják azokat az elemeket, kicserélték a sorozat, meg akarja találni

  • A legnagyobb helyi maximum a tömbben.
  • A legkisebb lokális minimum a tömbben.

Ez a két elem a helyén, és meg kell felcserélni.

Most nézzük gondolni, hogyan lehet alkalmazni ezt a fákat. Mivel a inorder séta a fa fog a rendezve szekvencia a két elem elromlott, az egyik lehetőség az lenne, hogy járni a fa, a rögzítés inorder elemsorozatával találtunk, akkor a fenti algoritmus. Vegyük például az eredeti BST:

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

Ha linearizálásában ez egy tömb, megkapjuk

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

Figyeljük meg, hogy a 16-nél nagyobb a környező elemeket, és hogy a 12 kisebb, mint az. Ez azonnal azt mondja, hogy a 12 és 16 kicserélték.

Egy egyszerű algoritmus megoldja ezt a problémát, ezért az lenne, hogy csinál egy inorder séta a fa linearizáljuk egy szekvencia, mint egy vectorvagy deque, akkor beolvasni, hogy a sorozatot, hogy megtalálják a legnagyobb helyi maximum, és a legkisebb lokális minimum. Ez fut O (n) időben, O (n) térben. Egy bonyolultabb, de több helyet-hatékony algoritmust az lenne, hogy csak nyomon követni a három csomópont egy időben - az aktuális csomópont, elődje, és utódja -, amely csökkenti a memória használat, hogy O (1).

Remélem ez segít!

Válaszolt 31/08/2011 21:22
a forrás felhasználó

szavazat
0

A fa bejárás történik templatetypedef akkor működik, ha biztos vagy benne, hogy csak egy csere. Egyébként én olyan megoldás alapján a kezdeti kód:

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

Ez lassabb, de kiírja a swap azonosítja. Meg lehet változtatni a nyomtatás minden megsértését (például ha (max_left> fa-> data) print megsértése). Meg lehet javítani a teljesítményét, ha felveheti két mező a TreeNode a maximum és minimum előre kiszámított adott részfa.

Válaszolt 01/09/2011 08:43
a forrás felhasználó

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