logo

Introducere în Red-Black Tree

Arbori binari de căutare sunt fundamentale structură de date, dar performanța lor poate avea de suferit dacă arborele devine dezechilibrat. Copaci Roșii Negri sunt un tip de arbore de căutare binar echilibrat care folosesc un set de reguli pentru a menține echilibrul, asigurând complexitatea timpului logaritmic pentru operațiuni precum inserarea, ștergerea și căutarea , indiferent de forma inițială a copacului. Copaci Roșii Negri se auto-echilibrează, folosind o schemă simplă de codare a culorilor pentru a ajusta arborele după fiecare modificare.

Actrița Sai Pallavi

Arborele Roșu-Negru



Cuprins

Ce este un copac roșu-negru?

A Arborele Roșu-Negru este o autoechilibrare arbore binar de căutare unde fiecare nod are un atribut suplimentar: o culoare, care poate fi fie roșu sau negru . Obiectivul principal al acestor arbori este menținerea echilibrului în timpul inserărilor și ștergerii, asigurând recuperarea și manipularea eficientă a datelor.

Proprietățile arborilor roșu-negru

A Arborele Roșu-Negru au urmatoarele proprietati:



  1. Culoarea nodului : Fiecare nod este fie roșu, fie negru .
  2. Proprietatea rădăcină : Rădăcina copacului este întotdeauna negru .
  3. Proprietatea Rosie : Nodurile roșii nu pot avea copii roșii (nu există două noduri roșii consecutive pe nicio cale).
  4. Proprietatea Neagră : Fiecare cale de la un nod la nodurile sale nule descendente (frunze) are același număr de negru noduri.
  5. Proprietatea frunzelor : Toate frunzele (nodurile NIL) sunt negru .

Aceste proprietăți asigură că cea mai lungă cale de la rădăcină la orice frunză nu este mai mare de două ori mai lungă decât cea mai scurtă cale, menținând echilibrul și performanța eficientă a copacului.

Exemplu de arbore roșu-negru

The Arbore roșu-negru corect în imaginea de mai sus se asigură că fiecare cale de la rădăcină la un nod frunză are același număr de noduri negre. În acest caz, există unul (excluzând nodul rădăcină).



The Arbore roșu negru incorect nu urmeaza proprietatile rosu-negru ca două noduri roșii sunt adiacente unul altuia. O altă problemă este că una dintre căile către un nod frunză are zero noduri negre, în timp ce celelalte două conțin un nod negru.

traversarea copacilor

De ce copaci roșu-negri?

Majoritatea operațiunilor BST (de exemplu, căutare, max, min, inserare, ștergere etc.) iau Oh) timp în care h este înălțimea lui BST . Costul acestor operațiuni poate deveni Pe) pentru o înclinată Arbore binar. Dacă ne asigurăm că înălțimea copacului rămâne O(log n) după fiecare inserare și ștergere, atunci putem garanta o limită superioară a O(log n) pentru toate aceste operațiuni. Înălțimea unui copac roșu-negru este întotdeauna O(log n) unde n este numărul de noduri din arbore.

domnule nr.AlgoritmComplexitatea timpului
1.CăutareO(log n)
2.IntroduceO(log n)
3.ȘtergeO(log n)

Comparație cu Arborele AVL :

Arborii AVL sunt mai echilibrați în comparație cu arborii roșu-negru, dar pot provoca mai multe rotații în timpul inserării și ștergerii. Deci, dacă aplicația dvs. implică inserări și ștergeri frecvente, atunci arborii roșu-negru ar trebui să fie preferați. Și dacă inserările și ștergerile sunt mai puțin frecvente și căutarea este o operațiune mai frecventă, atunci arborele AVL ar trebui să fie preferată Arborele Roșu-Negru.

Cum asigură un copac roșu-negru echilibrul?

Un exemplu simplu pentru a înțelege echilibrarea este că un lanț de 3 noduri nu este posibil în arborele Roșu-Negru. Putem încerca orice combinație de culori și să vedem dacă toate încalcă proprietatea arborelui roșu-negru.

Structura corectă a copacului cu trei noduri roșu-negru

Puncte interesante despre Red-Black Tree:

  • The negru înălțimea arborelui roșu-negru este numărul de noduri negre de pe o cale de la nodul rădăcină la un nod frunză. Nodurile frunzelor sunt, de asemenea, numărate ca negru noduri. Deci, un copac roșu-negru de înălțime h are înălțimea neagră>= h/2 .
  • Înălțimea unui copac roșu-negru cu n noduri este h<= 2 log 2 (n + 1) .
  • Toate frunzele (NIL) sunt negru .
  • The negru adâncimea unui nod este definită ca numărul de noduri negre de la rădăcină la acel nod, adică numărul de strămoși negri.

Operații de bază pe arborele roșu-negru:

Operațiunile de bază pe un arbore roșu-negru includ:

  1. Inserare
  2. Căutare
  3. Ștergere
  4. Rotație

1. Inserare

Inserarea unui nou nod într-un arbore roșu-negru implică un proces în doi pași: realizarea unui standard inserarea arborelui de căutare binar (BST). , urmată de remedierea oricăror încălcări ale proprietăților Roșu-Negru.

care este dimensiunea ecranului computerului meu

Etape de inserare

  1. Inserție BST : Inserați noul nod ca într-un BST standard.
  2. Remediați încălcările :
    • Dacă părintele noului nod este negru , nu sunt încălcate proprietăți.
    • Dacă părintele este roșu , arborele ar putea încălca proprietatea roșie, necesitând remedieri.

Remedierea încălcărilor în timpul inserării

După introducerea noului nod ca a roșu nod, am putea întâlni mai multe cazuri în funcție de culorile părintelui și unchiului nodului (fratele părintelui):

  • Cazul 1: Unchiul este roșu : Recolorează părintele și unchiul la negru , iar bunicul să roșu . Apoi deplasați-vă în sus pentru a verifica dacă există încălcări suplimentare.
  • Cazul 2: Unchiul este negru :
    • Subcazul 2.1: Nodul este un copil potrivit : Efectuați o rotație la stânga asupra părintelui.
    • Subcazul 2.2: Nodul este un copil stâng : Efectuați o rotație dreaptă asupra bunicului și recolorați corespunzător.

2. Căutarea

Căutarea unui nod într-un arbore roșu-negru este similară cu căutarea într-un standard Arborele de căutare binar (BST) . Operația de căutare urmează o cale directă de la rădăcină la a frunze , comparând valoarea țintă cu valoarea nodului curent și deplasându-se la stânga sau la dreapta în consecință.

Pași de căutare

  1. Începeți de la rădăcină : Începeți căutarea la nodul rădăcină.
  2. Traversează Copacul :
    • Dacă valoarea țintă este egală cu valoarea nodului curent, nodul este găsit.
    • Dacă valoarea țintă este mai mică decât valoarea nodului curent, treceți la copilul din stânga.
    • Dacă valoarea țintă este mai mare decât valoarea nodului curent, treceți la copilul din dreapta.
  3. Repeta : Continuați acest proces până când este găsită valoarea țintă sau este atins un nod NIL (indicând că valoarea nu este prezentă în arbore).

3. Ștergere

Ștergerea unui nod dintr-un arbore roșu-negru implică, de asemenea, un proces în doi pași: efectuarea ștergerii BST, urmată de remedierea oricăror încălcări care apar.

Pașii de ștergere

  1. Ștergere BST : Eliminați nodul folosind regulile BST standard.
  2. Fix Double Black :
    • Dacă un nod negru este șters, poate apărea o condiție de negru dublu, care necesită remedieri specifice.

Remedierea încălcărilor în timpul ștergerii

Când un nod negru este șters, ne ocupăm de problema dublu negru în funcție de culoarea fratelui și de culorile copiilor săi:

  • Cazul 1: Fratele este roșu : Rotiți părintele și recolorați fratele și părintele.
  • Cazul 2: Fratele este negru :
    • Subcazul 2.1: Copiii fraților sunt negri : Recolorează fratele și propagă negrul dublu în sus.
    • Subcazul 2.2: Cel puțin unul dintre copiii fratelui este roșu :
      • Dacă copilul îndepărtat al fratelui este roșu : Efectuați o rotație asupra părintelui și a fratelui și recolorați corespunzător.
      • Dacă copilul apropiat al fratelui este roșu : Rotiți fratele și copilul acestuia, apoi manipulați ca mai sus.

4. Rotire

Rotațiile sunt operațiuni fundamentale în menținerea structurii echilibrate a unui arbore roșu-negru (RBT). Ele ajută la păstrarea proprietăților copacului, asigurându-se că cea mai lungă cale de la rădăcină la orice frunză nu este mai mare de două ori lungimea celei mai scurte căi. Rotațiile sunt de două tipuri: rotații la stânga și rotatii la dreapta.

1. Rotire la stânga

O rotație la stânga la nodul 𝑥 X se mișcă 𝑥 X jos la stânga și copilul său drept 𝑦 și până să ia 𝑥 X locul lui.

Vizualizarea rotației la stânga
Before Rotation:  x      y   /    a b  After Left Rotation:  y  /   x b  /  a>

Pași de rotație la stânga:

  1. A stabilit și a fi copilul potrivit al X .
  2. Mișcare și subarborele din stânga lui X subarborele corect.
  3. Actualizați părintele lui X și și .
  4. Actualizați X părintele lui să arate și în loc de X .
  5. A stabilit și i-a lăsat copilul să X .
  6. Actualizați X părintele lui și .

Pseudocod de rotație la stânga:

Rotație la stânga
// Utility function to perform left rotation void leftRotate(Node* x) {  Node* y = x->dreapta;  x->dreapta = y->stânga;  if (y->left != NIL) { y->left->parent = x;  } y->parent = x->parent;  if (x->parent == nullptr) { root = y;  } else if (x == x->parent->left) { x->parent->left = y;  } else { x->părinte->dreapta = y;  } y->stânga = x;  x->părinte = y; }>>> 

2. Rotire dreapta

O rotație la dreapta la nodul 𝑥 X se mișcă 𝑥 X jos în dreapta și copilul său stâng 𝑦 și până să ia 𝑥 X locul lui.

Vizualizarea rotației la dreapta: Pașii de rotație la dreapta:
  1. A stabilit și a fi copilul stâng al X .
  2. Mișcare și subarborele potrivit pentru X subarborele din stânga lui.
  3. Actualizați părintele lui X și și .
  4. Actualizați X părintele lui să arate și în loc de X .
  5. A stabilit și copilul potrivit X .
  6. Actualizați X părintele lui și .

Pseudocod de rotație la dreapta:

C++
// Utility function to perform right rotation void rightRotate(Node* x) {  Node* y = x->stânga;  x->stânga = y->dreapta;  dacă (y->dreapta != NIL) { y->dreapta->părinte = x;  } y->parent = x->parent;  if (x->parent == nullptr) { root = y;  } else if (x == x->părinte->dreapta) { x->părinte->dreapta = y;  } else { x->parent->left = y;  } y->dreapta = x;  x->părinte = y; }>>> 

Când se efectuează rotații?

Rotațiile în arbori roșu-negru sunt de obicei efectuate în timpul inserărilor și ștergerii pentru a menține proprietățile arborelui. Mai jos sunt scenariile pentru rotații:

declarația bash if

1. Remedierea încălcărilor după inserare

Când este introdus un nou nod, acesta este întotdeauna colorat în roșu. Acest lucru poate crea încălcări ale proprietăților arborelui roșu-negru, în special:

  • Rădăcina trebuie să fie negru .
  • roșu nodurile nu pot avea roșu copii.

Analiza cazului pentru fixarea inserțiilor:

  • Cazul 1: Recolorarea și propagarea în sus
    • Dacă părintele și unchiul noului nod sunt amândoi roșu , recolorează părintele și unchiul la negru , iar bunicul să roșu . Apoi, aplicați recursiv remedierea bunicului.
  • Cazul 2: Rotire și Recolorare
    • Dacă unchiul noului nod este negru iar noul nod este copilul drept al unui copil stâng (sau invers), efectuați o rotație pentru a muta noul nod în sus și a-l alinia.
    • Dacă unchiul noului nod este negru iar noul nod este copilul stâng al unui copil stâng (sau dreapta unui drept), efectuați o rotație și recolorați părintele și bunicul pentru a remedia încălcarea.

2. Remedierea încălcărilor după ștergere

După ștergere, arborele ar putea avea nevoie de reparații pentru a restabili proprietățile:

  • Când un nod negru este îndepărtat sau un nod roșu este înlocuit cu un nod negru, poate apărea o situație de dublu negru.

Analiza cazului pentru remedierea ștergerilor:

  • Cazul 1: Fratele este roșu
    • Recolorează fratele și părintele și efectuează o rotație.
  • Cazul 2: Fratele este negru cu copii negri
    • Recolorați fratele în roșu și mutați problema la părinte.
  • Cazul 3: Fratele este negru cu cel puțin un copil roșu
    • Rotiți și recolorați pentru a remedia problema dublu-negru.

Implementarea arborelui roșu-negru:

Iată o implementare detaliată a unui arbore roșu-negru, inclusiv funcții de inserare, căutare și rotație:

C++dreapta; x->dreapta = y->stânga; if (y->left != NIL) { y->left->parent = x; } y->parent = x->parent; if (x->parent == nullptr) { root = y; } else if (x == x->parent->left) { x->parent->left = y; } else { x->părinte->dreapta = y; } y->stânga = x; x->părinte = y; } // Funcție utilitar pentru a efectua rotația la dreapta void rightRotate(Nod* x) { Nod* y = x->left; x->stânga = y->dreapta; dacă (y->dreapta != NIL) { y->dreapta->părinte = x; } y->parent = x->parent; if (x->parent == nullptr) { root = y; } else if (x == x->părinte->dreapta) { x->părinte->dreapta = y; } else { x->parent->left = y; } y->dreapta = x; x->părinte = y; } // Funcție pentru a remedia proprietățile arborelui roșu-negru după // inserare void fixInsert(Node* k) { while (k != root && k->parent->color == 'RED') { if (k->părinte == k->părinte->părinte->stânga) { Nodul* u = k->părinte->părinte->dreapta; // uncle if (u->color == 'RED') { k->parent->color = 'BLACK'; u->culoare = 'NEGRU'; k->parent->parent->culoare = 'RED'; k = k->părinte->părinte; } else { if (k == k->părinte->dreapta) { k = k->părinte; stângaRotire(k); } k->parent->culoare = 'NEGRU'; k->parent->parent->culoare = 'RED'; dreaptaRotate(k->părinte->părinte); } } else { Nod* u = k->parent->parent->left; // uncle if (u->color == 'RED') { k->parent->color = 'BLACK'; u->culoare = 'NEGRU'; k->parent->parent->culoare = 'RED'; k = k->părinte->părinte; } else { if (k == k->părinte->stânga) { k = k->părinte; dreaptaRotire(k); } k->parent->culoare = 'NEGRU'; k->parent->parent->culoare = 'RED'; stângaRotire(k->părinte->părinte); } } } root->color = 'NEGRU'; } // Inorder traversal helper function void inorderHelper(Nod* node) { if (nod != NIL) { inorderHelper(nod->left); cout<< node->date<< ' '; inorderHelper(node->dreapta); } } // Funcția de ajutor de căutare Nod* searchHelper(Nod* nod, int date) { if (nod == NIL || data == node->data) { return node; } dacă (date< node->date) { return searchHelper(nod->stânga, date); } return searchHelper(nod->dreapta, date); } public: // Constructor RedBlackTree() { NIL = new Node(0); NIL->culoare = 'NEGRU'; NIL->stânga = NIL->dreapta = NIL; rădăcină = NIL; } // Funcția de inserare void insert(int data) { Nod* new_node = new Node(data); nod_nou->stânga = NIL; nod_nou->dreapta = NIL; Nod* parent = nullptr; Nod* curent = rădăcină; // BST introduce while (current != NIL) { parent = current; if (nod_nou->date< current->date) { curent = curent->stânga; } else { curent = curent->dreapta; } } nod_nou->părinte = părinte; if (parent == nullptr) { root = new_node; } else if (nod_nou->date< parent->date) { parent->left = new_node; } else { parent->right = new_node; } if (nod_nou->părinte == nullptr) { nod_nou->culoare = 'NEGRU'; întoarcere; } if (nod_nou->părinte->părinte == nullptr) { return; } fixInsert(nod_nou); } // Inorder traversal void inorder() { inorderHelper(root); } // Funcția de căutare Nod* search(int data) { return searchHelper(root, data); } }; int main() { RedBlackTree rbt; // Inserarea elementelor rbt.insert(10); rbt.inserat(20); rbt.inserat(30); rbt.insert(15); // Inorder traversal cout<< 'Inorder traversal:' << endl; rbt.inorder(); // Output: 10 15 20 30 // Search for a node cout << ' Search for 15: ' << (rbt.search(15) != rbt.search(0)) << endl; // Output: 1 (true) cout << 'Search for 25: ' << (rbt.search(25) != rbt.search(0)) << endl; // Output: 0 (false) return 0; }>

Avantajele copacilor roșu-negru:

  • Echilibrat: Copacii roșu-negru se auto-echilibrează, ceea ce înseamnă că mențin automat un echilibru între înălțimile subarborilor din stânga și din dreapta. Acest lucru asigură că operațiunile de căutare, inserare și ștergere necesită timp O(log n) în cel mai rău caz.
  • Căutare, inserare și ștergere eficiente: Datorită structurii lor echilibrate, Copacii Roșu-Negru oferă operațiuni eficiente. Căutarea, inserarea și ștergerea necesită timp O(log n) în cel mai rău caz.
  • Simplu de implementat: Regulile pentru menținerea proprietăților arborelui roșu-negru sunt relativ simple și ușor de implementat.
  • Utilizate pe scară largă: Arborii roșu-negru sunt o alegere populară pentru implementarea diferitelor structuri de date, cum ar fi hărți, seturi și cozi de prioritate.

Dezavantajele copacilor roșu-negru:

  • Mai complex decât alți arbori echilibrați: În comparație cu arborii echilibrați mai simpli precum arborii AVL, arborii roșu-negru au reguli de inserare și ștergere mai complexe.
  • Costul general constant: Menținerea proprietăților arborelui roșu-negru adaugă o mică suprasarcină la fiecare operație de inserare și ștergere.
  • Nu este optim pentru toate cazurile de utilizare: Deși eficient pentru majoritatea operațiunilor, Red-Black Trees ar putea să nu fie cea mai bună alegere pentru aplicațiile în care sunt necesare inserări și ștergeri frecvente, deoarece suprasolicitarea constantă poate deveni semnificativă.

Aplicații ale arborilor roșu-negru:

  • Implementarea de hărți și seturi: Arborele roșu-negru sunt adesea folosiți pentru a implementa hărți și seturi, unde căutarea, inserarea și ștergerea eficiente sunt cruciale.
  • Cozile prioritare: Arborii roșu-negru pot fi utilizați pentru a implementa cozi de prioritate, în care elementele sunt ordonate în funcție de prioritatea lor.
  • Sisteme de fișiere: Arborii roșu-negru sunt utilizați în unele sisteme de fișiere pentru a gestiona structurile de fișiere și directoare.
  • Baze de date în memorie: Arborele roșu-negru sunt uneori folosiți în bazele de date în memorie pentru a stoca și a prelua datele în mod eficient.
  • Dezvoltare grafică și joc: Red-Black Trees poate fi folosit în grafică și joc dezvoltare pentru sarcini precum detectarea coliziunilor și identificarea căii.

Întrebări frecvente (FAQs) despre Red-Black Tree:

1. Ce este un copac roșu-negru?

Un arbore roșu-negru este un arbore de căutare binar cu auto-echilibrare care menține un echilibru între înălțimile subarborilor din stânga și din dreapta. Acest lucru asigură că operațiunile de căutare, inserare și ștergere necesită timp O(log n) în cel mai rău caz. Arborele roșu-negru sunt utilizați pe scară largă în diverse aplicații în care sunt necesare structuri eficiente de date.

2. Cum își menține echilibrul un copac roșu-negru?

Arborele Roșu-Negru își mențin echilibrul prin aplicarea unor reguli specifice privind culorile nodurilor (ROȘU sau NEGRU) și relațiile dintre ele. Aceste reguli asigură că arborele rămâne echilibrat și că diferența de înălțime dintre subarborele din stânga și din dreapta este de cel mult 1.

3. Care sunt avantajele folosirii unui arbore roșu-negru?

  • Echilibrat: Arborele roșu-negru se auto-echilibrează, asigurând operațiuni eficiente de căutare, inserare și ștergere.
  • Eficient: Ele oferă complexitate de timp O(log n) pentru majoritatea operațiunilor.
  • Simplu de implementat: Regulile pentru menținerea proprietăților arborelui roșu-negru sunt relativ simple.
  • Utilizate pe scară largă: Sunt o alegere populară pentru implementarea diferitelor structuri de date și algoritmi.

4. Care sunt dezavantajele folosirii unui arbore roșu-negru?

  • În comparație cu arborii echilibrați mai simpli precum arborii AVL, arborii roșu-negru au reguli de inserare și ștergere mai complexe.
  • Menținerea proprietăților arborelui roșu-negru adaugă o mică suprasarcină la fiecare operație de inserare și ștergere.
  • Pentru aplicațiile cu inserții și ștergeri frecvente, alte structuri de arbore echilibrate ar putea fi mai potrivite.

5. Care sunt câteva aplicații comune ale arborilor roșu-negru?

  • Implementarea de hărți și seturi
  • Cozile prioritare
  • Sisteme de fișiere
  • Baze de date în memorie
  • Dezvoltare grafică și joc (detecția coliziunilor, identificarea căii)
  • Definiția și semnificația arborelui roșu-negru în DSA
  • Arbori de căutare binari cu auto-echilibrare
  • Red Black Tree vs AVL Tree
  • Care este diferența dintre Heap și Red-Black Tree?
  • Inserție în arbore roșu-negru
  • Ștergere în arbore roșu-negru
  • Copaci roșu-negri | Inserție de sus în jos