Finn byttet noder i en BST

stemmer
6

Jeg prøver å skrive et program som kan oppdage og skrive ut to noder i BST som har blitt byttet.

I en tre nivå tre, jeg nådde nær til løsningen ved hjelp av denne tilnærmingen.

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

men ovenfor tilnærmingen feilet da jeg prøvde å teste med fire nivå tre.

             20

      15            30

   10    17       25     33

9  16  12  18  22  26  31  34

Å være i rotnoden 15 rett treet, 12 er enda større (brudd).

Å være i rotnoden 15 venstre treet, 16 er enda større (brudd).

Så, 16, 12 er de byttet elementer i den ovenfor BST. Hvordan finner jeg dem gjennom programmet?

Publisert på 31/08/2011 klokken 16:30
kilden bruker
På andre språk...                            


3 svar

stemmer
0

Jeg antar din getMin et getMax fungerer witht hypotesene at treet er en BST, så

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

(Eller den tilsvarende kode med en løkke). Hvis ja, undersøker koden på det meste tre verdiene i treet. Selv om getMax og getMin krysset hele treet for å få den faktiske max / min, ville du fortsatt basere testen på bare to sammenligninger. Hvis du ønsker å kontrollere at treet tilfreds BST eiendom, er det åpenbart at du må undersøke alle verdiene. Dens nok til å sammenligne hver node med sin overordnede.

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 : det var galt, se kommentar. Jeg tror dette er 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
}

Ringe fra rot med null grenser

Svarte 31/08/2011 kl. 17:03
kilden bruker

stemmer
8

En måte å tenke på dette problemet er å bruke det faktum at en inorder gange fra treet vil produsere alle elementene i sortert rekkefølge. Hvis du kan oppdage avvik fra sortert rekkefølge i løpet av denne turen, kan du prøve å finne de to elementer som er på feil sted.

La oss se hvordan du gjør dette for en enkel sortert utvalg først, deretter vil bruke vår algoritme for å bygge noe som fungerer på trær. Intuitivt, hvis vi starter med en sortert array og deretter bytte to (ikke-like!) Elementer, vil vi ende opp med et antall elementer i tabellen være malplassert. For eksempel, gitt matrisen

1 2 3 4 5

Hvis vi bytter to og fire, ender vi opp med denne matrisen:

1 4 3 2 5

Hvordan ville vi oppdage at to og fire ble byttet her? Også, siden 4 er det største av de to elementer og er byttet nedover, bør det være større enn begge av elementene rundt det. På samme måte, fordi 2 ble byttet opp, bør det være mindre enn begge av elementene rundt det. Fra dette kan vi konkludere med at 2 og 4 ble byttet.

Men dette fungerer ikke alltid riktig. For eksempel anta at vi bytter 1 og 4:

4 2 3 1 5

Her, både 2 og 1 er mindre enn sine naboelementer, og både 4 og 3 er større enn deres. Fra dette kan vi fortelle at to av disse fire liksom ble byttet, men det er ikke klart hvilke vi skal utveksle. Men hvis vi tar den største og den minste av disse verdiene (1 og 4, henholdsvis), ender vi opp med å få paret som ble byttet.

Mer generelt, for å finne de elementene som ble byttet i sekvensen, vil du finne

  • Den største lokalt maksimum i rekken.
  • Den minste lokalt minimum i matrisen.

Disse to elementer er på plass og skal byttes.

Nå, la oss tenke på hvordan du kan bruke dette til trær. Siden en inorder gange fra treet vil produsere sortert sekvens med de to elementene i rekkefølge, ville ett alternativ være å gå treet, innspilling inorder sekvens av elementer vi har funnet, deretter bruke algoritmen ovenfor. For eksempel vurdere den opprinnelige BST:

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

Hvis vi linear dette inn i en matrise, får vi

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

Legg merke til at 16 er større enn dets omkringliggende elementer og det 12 er mindre enn dens. Dette forteller oss umiddelbart at 12 og 16 ble byttet.

En enkel algoritme for å løse dette problemet, derfor ville være å gjøre en inorder gange fra treet for å linear det inn i en sekvens som en vectoreller deque, deretter for å skanne den sekvensen for å finne den største lokale maksimums- og den minste lokale minimum. Dette vil bli kjørt i O (N) tid, ved anvendelse av O (n) plass. En mer komplisert men mer plass effektiv algoritme vil være å bare holde styr på tre noder på en gang - den aktuelle node, forgjengeren, og dens etterfølger - som reduserer minnebruken til O (1).

Håper dette hjelper!

Svarte 31/08/2011 kl. 20:22
kilden bruker

stemmer
0

treet traversering gjøres ved templatetypedef fungerer hvis du er sikker på at det bare er en swap. Ellers foreslår jeg at en løsning basert på den opprinnelige kode:

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

Det er tregere, men det skrives alle swapper den identifiserer. Kan endres til å skrive ut alle brudd (f.eks if (max_left> tre-> data) print brudd). Du kan forbedre ytelsen hvis du kan legge til to felt i TreeNode med max og min forhåndsberegnede for at treet.

Svarte 01/09/2011 kl. 07:43
kilden bruker

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