Vind verwisseld knooppunten in een BST

stemmen
6

Ik ben op zoek naar een programma dat kan detecteren en twee knooppunten in BST die zijn verwisseld drukken schrijven.

In een drie-level boom, bereikte ik in de buurt van de oplossing om met deze aanpak.

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

maar de bovenstaande aanpak mislukte toen ik probeerde om te testen met vier niveaus boom.

             20

      15            30

   10    17       25     33

9  16  12  18  22  26  31  34

Als je in rechter deelboom root node 15's, 12 nog steeds groter is (overtreding).

Waarbij in de linker deelboom root node 15 is, 16 is steeds groter (overtredingen).

Dus, 16, 12 verwisseld zijn de elementen in de bovenstaande BST. Hoe vind ik ze via het programma?

De vraag is gesteld op 31/08/2011 om 17:30
bron van user
In andere talen...                            


3 antwoorden

stemmen
0

Ik denk dat je getMin et getMax werkt witht de hypothesen dat de boom is een BST, dus

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

(Of gelijkwaardige code met een lus). Als dat zo is, de code onderzoekt ten hoogste drie waarden in de boom. Zelfs als getMax en getMin de volledige boom om de werkelijke max / min krijgen doorkruist, zou je nog baseren uw test op slechts twee vergelijkingen. Als u wilt controleren of uw boom aan de woning BST, is het duidelijk dat je moet alle waarden te onderzoeken. Het is genoeg om elk knooppunt met zijn ouders te vergelijken.

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
}

Bewerken : dat verkeerd was, zie commentaar. Ik denk dat dit is 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
}

Belt vanuit wortel null grenzen

antwoordde op 31/08/2011 om 18:03
bron van user

stemmen
8

Een manier om na te denken over dit probleem is het feit dat een inorder lopen van de boom alle elementen in gesorteerde volgorde zal produceren gebruiken. Als u tijdens deze wandeling afwijkingen van de gesorteerde volgorde kan detecteren, kunt u proberen om de twee elementen die op de verkeerde plaats te vinden.

Laten we eens kijken hoe dit voor een eenvoudige gesorteerde array eerst doen, dan zal ons algoritme te gebruiken om iets dat werkt op bomen te bouwen. Intuïtief Als we beginnen met een gesorteerde array en wisselen twee (niet-gelijke!) Elementen, zullen eindigen met enig aantal elementen in de array zijn misplaatst. Gegeven bijvoorbeeld de matrix

1 2 3 4 5

Als we ruilen 2 en 4, komen we uit op deze array:

1 4 3 2 5

Hoe zouden we detecteren dat 2 en 4 werden hier verwisseld? Goed, aangezien 4 is de grootste van de twee elementen en is naar beneden verwisseld, moet groter zijn dan beide elementen eromheen. Evenzo, omdat 2 werd verwisseld op, moet kleiner zijn dan beide elementen eromheen. Hieruit kunnen we concluderen dat 2 en 4 werden verwisseld.

Dit betekent echter niet altijd goed werken. Stel bijvoorbeeld dat we ruilen 1 en 4:

4 2 3 1 5

Hier zijn zowel 2 en 1 kleiner zijn dan de aangrenzende elementen, en zowel 4 en 3 zijn groter dan die van hen. Hieruit kunnen we zeggen dat twee van deze vier een of andere manier werden verwisseld, maar het is niet duidelijk welke we moeten verwisselen. Echter, als we de grootste en de kleinste van deze waarden (1 en 4, respectievelijk), eindigen we krijgen van het paar, dat werd omgezet.

Meer in het algemeen, om de elementen die werden verwisseld in de volgorde te vinden, die u wilt zoeken

  • De grootste lokale maximum in de array.
  • De kleinste lokale minimum in de array.

Deze twee elementen misplaatst en moet worden verwisseld.

Laten we nu eens na te denken over hoe dit van toepassing op bomen. Aangezien een inorder lopen van de boom zal de gesorteerde volgorde met de twee elementen in de juiste volgorde te produceren, zou een optie zijn om de boom te lopen, het opnemen van de inorder opeenvolging van elementen die we hebben gevonden, vervolgens met behulp van het bovenstaande algoritme. Denk bijvoorbeeld aan de oorspronkelijke BST:

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

Als we dit te lineariseren in een array, krijgen we

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

Merk op dat 16 groter is dan de omliggende elementen en die 12 lager is dan zijn. Dit vertelt ons meteen dat 12 en 16 waren verwisseld.

Een eenvoudig algoritme voor het oplossen van dit probleem dan ook, zou zijn om te doen een inorder lopen van de boom om het te lineariseren in een reeks als een vectorof deque, dan aan deze reeks scannen naar de grootste lokale maximum en de kleinste lokaal minimum vinden. Dit zou zijn bij O (n) tijdstip en O (n) space. Een lastiger maar ruimtebesparende algoritme is om enige nummer drie knooppunten houden tegelijk - de huidige knoop, zijn voorganger en de opvolger - die het geheugengebruik te verminderen O (1).

Ik hoop dat dit helpt!

antwoordde op 31/08/2011 om 21:22
bron van user

stemmen
0

de boom traversal gedaan door templatetypedef werkt als je zeker weet dat er slechts één swap. Anders stel ik voor een oplossing op basis van uw oorspronkelijke code:

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

Het is langzamer, maar het drukt alle swaps het identificeert. Kan worden aangepast aan alle schendingen (bijvoorbeeld als (max_left> boom-> gegevens) afdrukken schending) te drukken. U kunt de prestaties verbeteren als u twee velden kan toevoegen aan de TreeNode met de max en min vooraf berekende voor die substructuur.

antwoordde op 01/09/2011 om 08:43
bron van user

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