Găsiți noduri schimbate într-un BST

voturi
6

Am încercat să scrie un program care poate detecta și imprima două noduri în BST care au fost schimbate.

Într-un copac trei nivel, am ajuns aproape la soluția folosind această abordare.

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

dar abordarea de mai sus nu a reușit atunci când am încercat să testeze cu patru copac nivel.

             20

      15            30

   10    17       25     33

9  16  12  18  22  26  31  34

Fiind în subarborele drept rădăcină nod 15, a 12 este încă mai mare (încălcare).

Fiind în subarborele stâng rădăcină nod 15, a 16 este încă mai mare (încălcare).

Deci, 16, 12 sunt elementele schimba in BST de mai sus. Cum pot să le găsesc prin intermediul programului?

Întrebat 31/08/2011 la 17:30
sursa de către utilizator
În alte limbi...                            


3 răspunsuri

voturi
0

Cred că dumneavoastră getMin et getMax funcționează witht ipotezele pe care arborele este un BST, așa

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

(Sau codul echivalent cu o buclă). În acest caz, codul examinează cel mult trei valori din copac. Chiar dacă getMax și getMin traversat copac pe deplin pentru a obține reale max / min, v-ar bazează încă testul pe doar două comparații. Dacă doriți să verificați dacă arborele satisface proprietatea BST, este evident că trebuie să examineze toate valorile. Este suficient sa pentru a compara fiecare nod cu părintele său.

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 : că a fost greșit, a se vedea în comentariu. Cred că asta este în regulă.

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
}

Apelarea la rădăcină cu limite nule

Publicat 31/08/2011 la 18:03
sursa de către utilizator

voturi
8

Un mod de a gândi despre această problemă este de a utiliza faptul că o plimbare inordine a arborelui va produce toate elementele în ordine sortată. Dacă se poate detecta abateri de la comanda sortată în timpul acestei mers pe jos, puteți încerca să localizeze cele două elemente care sunt în locul greșit.

Să vedem cum se face acest lucru pentru o matrice de sortat simplu în primul rând, atunci va folosi algoritmul nostru pentru a construi ceva care funcționează pe copaci. Intuitiv, dacă vom începe cu o matrice de sortat și apoi schimba două elemente (non-egale!), Vom termina cu un numar de elemente din matrice fiind din loc. De exemplu, având în matrice

1 2 3 4 5

Dacă vom face schimb de 2 și 4, vom termina cu această matrice:

1 4 3 2 5

Cum detectăm că 2 și 4 au fost schimbate aici? Ei bine, din moment ce 4 este cea mai mare dintre cele două elemente și a fost schimbat în jos, ar trebui să fie mai mare decât atât a elementelor din jurul ei. În mod similar, pentru că 2 a fost schimbat în sus, ar trebui să fie mai mică decât atât a elementelor din jurul ei. Din aceasta, am putea concluziona că 2 și 4 au fost schimbate.

Cu toate acestea, acest lucru nu funcționează întotdeauna corect. De exemplu, să presupunem că vom schimba 1 și 4:

4 2 3 1 5

Aici, ambele 2 și 1 sunt mai mici decât elementele învecinate, iar ambele 4 și 3 sunt mai mari decât ale lor. Din aceasta putem spune că două dintre aceste patru într-un fel au fost schimbate, dar nu este clar care dintre ele ar trebui să interschimba. Cu toate acestea, dacă luăm cea mai mare și cea mai mică dintre aceste valori (1 și 4, respectiv), vom ajunge obtinerea perechea care a fost schimbat.

Mai general, pentru a găsi elementele care au fost schimbate în secvența, pe care doriți să găsiți

  • Cel mai mare maxim local în matrice.
  • Cel mai mic minim local în matrice.

Aceste două elemente sunt în afara de loc și ar trebui să fie schimbate.

Acum, să ne gândim cum să-l aplice la copaci. De la o plimbare inordine a arborelui va produce secvența de sortat cu cele două elemente din ordine, o opțiune ar fi să meargă copac, înregistrând secvența inordine a elementelor care le-am găsit, apoi folosind algoritmul de mai sus. De exemplu, ia în considerare BST original:

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

Dacă ne linearize acest lucru într-o matrice, obținem

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

Observați că 16 este mai mare decât elementele sale înconjurătoare și că 12 este mai mică decât ei. Acest lucru ne spune imediat că 12 și 16 au fost schimbate.

Un algoritm simplu pentru rezolvarea acestei probleme, prin urmare, ar fi de a face o plimbare inordine de copac pentru a fi linearizat într - o secvență ca un vectorsau deque, apoi pentru a scana acea secvență pentru a găsi cea mai mare maxim local și cel mai mic minim local. Acest lucru ar fi în O (n), folosind O (n) spațiu. Un algoritm mai complicat , dar mult mai eficient din punct de spațiu ar fi să păstreze doar urmări trei noduri la un moment dat - nodul curent, predecesorul său, și succesorul său - care reduce utilizarea memoriei la O (1).

Sper că acest lucru vă ajută!

Publicat 31/08/2011 la 21:22
sursa de către utilizator

voturi
0

traversarea arborelui făcut de templatetypedef funcționează dacă sunteți sigur că nu există decât un singur schimb. În caz contrar , am sugera o soluție bazată pe codul inițial:

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

Este mai lent, dar se imprimă toate swap-urile pe care le identifică. Poate fi modificat pentru a imprima toate încălcările (de exemplu, în cazul în care (max_left> tree-> date) încălcarea de imprimare). Puteți îmbunătăți performanța în cazul în care aveți posibilitatea să adăugați două câmpuri la TreeNode cu max și min precalculate pentru subramificație.

Publicat 01/09/2011 la 08:43
sursa de către utilizator

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