Documente online.
Zona de administrare documente. Fisierele tale
Am uitat parola x Creaza cont nou
 HomeExploreaza
upload
Upload




Arborele binar de cautare (BST)

c


Arborele binar de cautare (BST)

Arborele binar de cautare reprezinta o solutie eficienta de implementare a structurii de date numite 'dictionar'. Vom considera o multime 'atomi'. Pentru fiecare element din aceasta multime avem: a I atomi, este definita o 838g67i functie numita cheie de cautare: key(a) I k cu proprietatea ca doi atomi distincti au chei diferite de cautare: a a T key(a key(a



Exemplu (abreviere, definitie) ('BST','Binary Search Tree')

('LIFO','Last In First Out') key(a) = a.abreviere

Un dictionar este o colectie S de atomi pentru care se definesc operatiile:

insert(S,a) insereaza atomul a in S daca nu exista deja;

delete(S,k) sterge atomul cu cheia k din S daca exista;

search(S,k) cauta atomul cu cheia k in S si-l returneaza sau determina daca nu este.

O solutie imediata ar fi retinerea elementelor din S intr-o lista inlantuita, iar operatiile vor avea complexitatea O(n).

Tabelele Hashing

Acestea sunt o alta solutie pentru a retine elementele din S. Complexitatea pentru arborele binar de cautare in cazurile:

cel mai defavorabil: O(n);

mediu: O(log n).

Un arbore binar de cautare este un arbore T ale carui noduri sunt etichetate cu atomii continuti la un moment dat in dictionar.

T = (V, E V= n. (n atomi in dictionar)

Considerand r I V (radacina arborelui), Ts subarborele stang al radacinii si Td subarborele drept al radacinii, atunci structura acestui arbore este definita de urmatoarele proprietati:

un nod x I Ts atunci key(data(x)) < key(data(r));

x I Td atunci key(data(x)) > key(data(r));

Ts si Td sunt BST.

Observatii:

Consideram ca pe multimea k este definita o relatie de ordine (de exemplu lexico-grafica);

Pentru oricare nod din BST toate nodurile din subarborele stang sunt mai mici decat radacina si toate nodurile din subarborele drept sunt mai mari decat radacina.

Exemple: 15 15

/ /

7 25 10 25

/ / / /

40 2 1 7 13

/ /

9

este BST nu este BST.

3) Inordine: viziteaza nodurile in ordine crescatoare a cheilor: 2 7 9 13 15 17 25 27 40 99

Functii:

Search:

search(rad,k)    // rad pointer la radacina arborelui

Insert:

Se va crea un nod in arbore care va fi plasat la un nou nod terminal. Pozitia in care trebuie plasat acesta este unic determinata in functie de valoarea cheii de cautare.

Exemplu: vom insera 19 in arborele nostru:

15

/

7 25

/ /

17 40

9 19

insert(rad,a)    // rad referinta la pointerul la radacina // arborelui

Functia make_nod creaza un nou nod:

make_nod(a)

Observatie:

La inserarea unui atom deja existent in arbore, functia insert nu modifica structura arborelui. Exista probleme in care este utila contorizarea numarului de inserari a unui atom in arbore.

Functia insert poate returna pointer la radacina facand apeluri de forma p= insert(p,a).

Delete:

delete(rad,k)    // rad referinta la pointer la radacina

Stergerea radacinii unui BST.:

rad T arbore vid

a) rad sau b) rad T a) SAS sau b) SAD

/

SAS SAD

delete_root(rad) // rad referinta la pointer la radacina

15

/

7 25

/ /

2 13 17 40

/ /

9 27

/

Detasarea din structura arborelui BST a celui mai mare nod (remove_greatest):

Pentru a gasi cel mai mare nod dintr-un arbore binar de cautare, se inainteaza in adancime pe ramura dreapta pana se gaseste primul nod care nu are descendent dreapta. Acesta va fi cel mai mare.

Vom trata aceasta procedura recursiv:

Caz1: rad T se returneaza pointer la radacina si arborele rezultat va fi vid.

Caz2: rad T se returneaza pointer la radacina si arborele rezultat va fi format doar din SAS subarborele stang (SAS).

Caz3 rad T functia returneaza pointer la cel mai mare nod din SAD, iar rezultatul va fi SAS arborele care este fomat din radacina,SAS si SAD cel mai mare nod.

remove_greatest(rad) //rad -referinta la pointer la //radacina: un pointer la radacina de poate

//fi modificat de catre functie

Observatie:

Functia remove_greatest modifica arborele indicat de parametru, in sensul eliminarii nodului cel mai mare, si intoarce pointer la nodul eliminat.

Demonstratia eficientei (complexitate)

Complexitatea tuturor functiilor scrise depinde de adancimea arborelui. In cazul cel mai defavorabil, fiecare functie parcurge lantul cel mai lung din arbore. Functia de cautare are, in acest caz, complexitatea O(n).

Structura arborelui BST este determinata de ordinea inserarii.

De exemplu, ordinea 15 13 12 11 este alta decat 15 12 11 13 .

Studiem un caz de complexitate medie:

Crearea unui BST pornind de la secventa de atomi (a a an

gen_BST (va fi in programul principal)

| rad= 0

| for i= 1 to n

| insert (rad, ai)

Calculam complexitatea medie a generarii BST:

Complexitatea in cazul cel mai defavorabil este:

Notam cu T(k) numarul de comparatii mediu pentru crearea unui BST pornind de la o secventa de k elemente la intrare. Ordinea celor k elemente se considera aleatoare.

Pentru problema T(n) avem de creat secventa (a a an cu observatia ca a este radacina arborelui. Ca rezultat, in urma primei operatii de inserare pe care o facem, rezulta:

a1

/

a1 ai

(ai<a1) (ai>a1)

Nu vom considera numararea operatiilor in ordinea in care apar ele, ci consideram numarul de operatii globale. Dupa ce am inserat a , pentru inserarea fiecarui element in SAS sau SAD a lui a , se face o comparatie cu a . Deci:

T(n)= (n - 1) + val.med.SAS + val.med.SAD

val.med.SAS = valoarea medie a numarului de comparatii necesar pentru a construi subarborele stang SAS

val.med.SAD = valoarea medie a numarului de comparatii necesar pentru a construi subarborele drept SAD

Notam:

Ti(n) = numarul mediu de comparatii necesar pentru construirea unui BST cu n noduri atunci cand prima valoare inserata (a ) este mai mare decat i-1 dintre cele n valori de inserat. Putem scrie:

Deci:

Deci:

Complexitatea acestei functii este: O(n ln n) (vezi curs 5 complexitatea medie a algoritmului Quick-Sort)

Arbori binari de cautare dinamic echilibrati (AVL)

Definitie

Un arbore binar este echilibrat daca si numai daca, pentru fiecare nod din arbore, diferenta dintre adancimile SAS si SAD in modul este

Exemple:

a a

/ /

b c b c

/ / /

d e f g d e f

/

g h

arbore binar arbore binar

complet echilibrat echilibrat

Adancimea unui arbore echilibrat cu n noduri este O(ln n).

Se completeaza operatiile insert si delete cu niste prelucrari care sa pastreze proprietatile de arbore binar echilibrat pentru arborele binar de cautare. Arborele binar echilibrat este un BST echilibrat, proprietatea de echilibrare fiind conservata de insert si delete. Efortul, in plus, pentru completarea operatiilor insert si delete nu schimba complexitatea arborelui binar echilibrat.

Transformarea structurii arborelui dupa inserare pentru a conserva proprietatea de arbore binar echilibrat

Modificarile care se vor face se vor numi rotatii.

Caz 1: Fie arborele echilibrat

A

/

B T3 h = depth(T ) = depth(T ) = depth(T

/

T T

Consideram arborii T1, T , T echilibrati. Inserand un nod prin rotatie simpla, rezulta structurile rotit simplu la dreapta si rotit simplu la stanga imaginea oglinda a rotatiei dreapta:

A A

/ /

B T T B

/ /

T T T T

Caz 2: Inserarea se face prin rotatii duble:

A A

/ /

B T T B

/ /

T T T T

rotatie dubla rotatie dubla

la dreapta la stanga

Fie primul caz:

A

/

B T

/

T T este BST: T < B < T < A < T

Toti arborii care respecta in continuare aceasta conditie vor fi BST.

Ridicand pe B in sus, si notand cu // legaturile neschimbate, rezulta:

B

//

// A

T

___________ _T _T pe aceeasi

linie

care este un BST , deci este arbore echilibrat, si are aceeasi adancime (!!!) cu arborele initial (de dinainte de inserare). Nodurile superioare nu sunt afectate. Rationament analog pentru imaginea oglinda.

Fie cazul 2: Pentru rotatia dubla se detaliaza structura arborelui T . Nu se poate sparge arborele initial ca in cazul 1.

A

/

B

// T

// C

T T2S T2D

depth(T ) = depth(T ) = h

depth(T2S) = depth(T2D) = h - 1

In urma inserarii, unul dintre arborii T2S si T2D isi mareste adancimea. Aplicam aceiasi tehnica:
T
< B < T2S < C < T2D < A < T

Incepem cu C:

C

/

B A

// /

// T2S T2D

____T T

la acelasi nivel

Rezulta un BST echilibrat, de aceeaai adancime cu arborele initial. Rotatiile sunt duble, in sensul ca
s-a facut o rotatie simpla B la stanga cu o rotatie simpla A la dreapta.

Operatiile care trebuiesc facute in cazul 1 (rotatie simpla la dreapta):

r pointer la nodul radacina (A)

a pointer la radacina

p = lchild(r)    b = lchild(a)

lchild(r) = rchild(p)    lchild(a) = rchild(b)

rchild(p) = r    rchild(b) = a

r = p a = b

Operatiile care trebuiesc facute in cazul 2 (rotatie dubla)

b = lchild(a)

c = rchild(b)

lchild(a) = rchild(c)

rchild(b) = lchild(c)

rchild(c) = a

lchild(c) = b

a = c // se schimba radacina arborelui.

Asadar, in inserarea prin rotatie se obtine un arbore echilibrat cu adancimea egala cu adancimea arborelui de dinainte de inserare. La inserarea unui nod terminal intr-un arbore AVL este necesara aplicarea a cel mult o rotatie asupra unui nod. Trebuie, deci sa gasim nodul asupra caruia trebuie aplicata rotatia. Reprezentam ramura parcursa de la radacina la nodul inserat:

x T bf = 1

y T bf = 0

z T bf = - 1 (bf = -2 dupa inserare)

w T bf = 0 (bf = 1 dupa inserare)

v T bf = 0 (bf = -1 dupa inserare)

nodul

inserat

S-a notat pentru fiecare nod bf balance factor (factor de dezechilibrare):

bf(nod) = depth (lchild (nod)) depth (rchild (nod))

adica este diferenta dintre adancimea subarborelui stang si adancimea subarborelui drept.

Calculam factorii de balansare dupa inserare.

Observatie: Pentru nodul terminal s-a schimbat adancimea si factorul de balansare; bf = -2 dupa inserare devine nod dezechilibrat. Trebuie aplicata, deci, echilibrarea.

Definitie:

Se numeste nod critic primul nod cu bf 0 intalnit la o parcurgere de jos in sus a ramurii care leaga nodul inserat de radacina.

Observatie: Toate nodurile din ramura care sunt pe nivele inferioare nodului critic vor capata bf = 1 sau
bf = -1.

La nodul critic exista doua situatii:

Nodul critic va fi perfect balansat (bf = 0), daca dezechilibrul creat de nodul inserat anuleaza dezechilibrul initial al nodului. In acest caz nu este nevoie de rotatie (el completeaza un gol in arbore).

Factorul de balansare devine bf = 2 sau bf = -2 atunci cand nodul inserat mareste dezechilibrul arborelui (s-a inserat nodul in subarborele cel mai mare). In acest caz, se aplica o rotatie in urma careia se schimba strucutra subarborelui, astfel incat noua radacina capata bf = 0, conservandu-se adancimea.

Concluzie: Problema conservarii proprietatii de echilibrare a arborelui se rezolva aplicand o rotatie asupra nodului critic numai atunci cand inserarea dezechilibreaza acest nod.

Costul suplimentar care trebuie suportat se materializeaza prin necesitatea ca in fiecare nod sa se memoreze factorul de dezechilibrare bf. Acesti factori de dezechilibrare vor fi actualizati in urma operatiilor de rotatie si inserare. Operatia de stergere intr-un AVL implica mai multe rotatii, ea nu se studiaza in acest curs.

Exemplu: Se da arborele cu urmatoarea structura:

55

20 80

/

10 35 90

/ /

5 30

Sa se insereze nodurile 15, apoi 7 si sa se echilibreze arborele

Inseram prima valoare 15. Comparam mai intai cu e in stanga lui, s.a.m.d. pana cand gasim locul ei in pozitia de mai jos. Pentru a doua valoare de inserat, 7, nodul critic este 55. El este dezechilibrat stanga. Deci, va fi echilibrat la valoarea 2. Este necesara aplicarea unei rotatii asupra radacinii.

55

/

20 80

/

10 35 90

5

7

Facem o identificare cu unul din desenele de echilibrare prezentate in cursul anterior. Se asociaza nodurile: 55 A

20 B etc.

T

20 ----------> noduri implicate

in

10 > rotatie

/ /

5 80

/

7 30 90

In urma unei rotatii simple, factorii de dezechilibru implicati in rotatie devin zero.

Fie o a treia valoare de inserat 3, apoi a patra 9:

Nodul critic pentru 3 este 5, iar pentru 9 este este 10. Dupa rotatia aplicata (T2D, T2S vizi), rezulta arborele:

20

/

7 55

/ /

5 10 35 80

/ / /

3 30 90

La rotatia dubla, daca nodul 9 a fost inserat in subarborele T2S

B are bf = 0 |

A are bf = -1 | exceptie facand nodul C nodul de inserat

La rotatia dubla, daca nodul 9 a fost inserat in subarborele T2D

B are bf = 1 |

A are bf = 0 | exceptie facand nodul C nodul de inserat

Reprezentarea implicita a arborilor binari

In acest mod de reprezentare se reprezinta arborele printr-un tablou. Fie un arbore binar complet:

a

/

b c

/ /

d e f g

h i j k l m n o

care are 4 nivele, deci 24 - 1 = 15 noduri.

Asociem acestui arbore un vector V:

structurat astfel: radacina, nivelul 1 de la stanga la dreapta, nodurile nivelului 2 de la stanga la dreapta, etc, despartite de linii duble.

Lema

Daca in vectorul V un nod x este reprezentat prin elementul de vector V(i), atunci:

left_child(x) este reprezentat in elementul de vector V [2·i];

right_child(x) este reprezentat in elementul de vector V [2·i + 1];

parent(x) este reprezentat in elementul de vector V [[i/2]]

cu observatia ca paranteza patrata interioara este partea intrega.

Demonstratie:

Se face inductie dupa i:

Pentru i = 1 T V[1] radacina

T V[2] left_child(rad)

T V[3] right_child(rad)

Presupunem adevarata lema pentru elementul V[i] T V[2i] left_child

V[2i + 1] right_child

Elementul V[i + 1] este nodul urmator (de pe acelsi nivel sau de pe nivelul urmator) intr-o parcurgere binara.

V[i + 1] T left_child in V[2i + 2] = V[2(i + 1)]

right_child in V[2i + 3] = V[2(i + 1) + 1]

Daca avem un arbore binar care nu este complet, reprezentarea lui implicita se obtine completandu-se structura arborelui cu noduri fictive pana la obtinerea unui arbore binar complet.

Arbori heap (heap gramada)

Definitie:

Se numeste arbore heap un arbore binar T = (V, E) cu urmatoarele proprietati:

functia key : V R care asociaza fiecarui nod o cheie.

un nod v I V cu degree(v) > 0 (nu este nod terminal), atunci:

key(v) > key(left_child(v)), daca left_child(v)

key(v) > key(right_child(v)), daca right_child(v)

(Pentru fiecare nod din arbore, cheia nodului este mai mare decat cheile descendentilor).

Exemplu: 99

/

50 30

/ /

45 20 25 23

Observatie: De obicei functia cheie reprezinta selectia unui subcamp din campul de date memorate in nod.

Aplicatii ale arborilor heap

Coada cu prioritate;

Algoritmul Heap_Sort

Arborii heap nu se studiaza complet in acest curs.

Coada cu prioritati

Este o structura de date pentru care sunt definite urmatoarele operatii:

insert (S,a) - insereaza un atom in structura,

remove (S) - extrage din structura atomul cu cheia cea mai mare.

O coada cu prioritati poate fi implementata printr-o lista. Implementarea cozii cu prioritati prin lista permite definirea operatiilor insert si remove, in cazul cel mai bun, una este de complexitate O(1) si cealalta este de complexitate O(n).

Implementarea cozii cu prioritati prin heap face o echilibrare cu complexitatea urmatoare: una este de complexitate 0(log n) si cealalta de complexitate 0(log n).

Operatia de inserare

/

heap /

/ 50

/ /

30

/ / /

37 12 2

/ / / _________

15 7 | 42

----- ----- -------|

Acelasi arbore in reprezentare implicita:

Operatiile insert si remove pentru arbori heap au o forma foarte simpla cand utilizeaza reprezentarea implicita. Consideram, in continuare, arbori heap in reprezentare implicita.

Exemplu: un arbore cu ultimul nivel avand toate nodurile aliniate la stanga:

Inseram valoarea 42 T se adauga nodul la un nivel incomplet;

In reprezentarea implicita se adauga nodul la sfarsit.

insert

1) In reprezentarea implicita: V [N + 1] = a

N = N + 1

In continuare reorganizam structura arborelui astfel incat sa-si pastreze structura de heap.

2) Se utilizeaza interschimbarile. Comparatii:

Iau 2 indici: child = N si

parent = [N/2]

(in cazul nostru N = 11 si [N/2] = 5)

Comparam V[child] cu V[parent]

Interschimbare daca V[child] nu este mai mic decat V[parent] (se schimba 42 cu 37)

3) Inaintare in sus: child = parent

parent = [child/2]

4) Se reia pasul 2) pana cand nu se mai face interschimbarea.

Structura S este un arbore heap. El se afla in reprezentare implicita in 2 informatii:

V vector

N dimensiune

Operatia insert:

insert(V, N, a) // V vectorul ce contine reprezentarea

// implicita a heapu-lui;

// N numarul de noduri din heap,

// ambele sunt plasate

// prin referinta (functia insert

// le poate modifica);

// a atomul de inserat;

Operatia remove:

50

/

/ /

33 40 40 20

/ /

10 15 7 37 39

se scoate elementul cel mai mare care este radacina heap-ului; se initializeaza cei 2 indici;

se reorganizeaza structura arborilor: se ia ultimul nod de pe nivelul incomplet si-l aduc in nodul-radacina, si aceasta valoare va fi retrogradata pina cand structura heap-ului este realizata.

parent

conditia de heap /

lchild rchild

parent = max(parent, lchild, rchild).

Exista trei cazuri:

conditia este indeplinita deodata;

max este in stanga T retrogradarea se face in stanga;

max este in dreapta T retrogradarea se face in dreapta.

remove(V, N)

Complexitatea celor doua operatii insert si remove:

In cazul cel mai defavorabil se parcurge o ramura care leaga radacina de un nod terminal. La insert avem o comparatie, iar la remove avem doua comparatii. Rezulta, complexitatea este data de adancimea arborelui. Daca N este numarul de noduri din arbore, 2k N k+1 , si adancimea arborelui este k+1.

2k - 1 < N k+1 T k = [log N]

| |

nr. de noduri nr. de noduri

ale arborelui ale arborelui

complet de complet de

adancime k adancime k+1

k log N < k + 1 T adancimea arborelui este k = [log N]

Deci complexitatea este O(log N).

A doua aplicatie a heap-urilor este algoritmul Heap_Sort.

Algoritmul Heap_Sort

Heap_Sort(V, n)

Aceasta procedura sorteaza un vector V cu N elemente: transforma vectorul V intr-un heap si sorteaza prin extrageri succesive din acel heap.

Procedura Heap_Sort prin inserari repetate

heap_sort

Studiul complexitatii

Observatii:

Se fac mai multe operatii insert in heap-uri a caror dimensiune creste de la 1 la N;

Se fac n-1 opera_ii insert in heap-uri cu dimensiunea N n

Rezulta complexitatea acestor operatii nu depaseste O(n log n). Facem un studiu pentru a vedea daca nu cumva ea este mai mica decat O(n log n)

Cazul cel mai defavorabil este situatia in care la fiecare inserare se parcurge o ramura completa. De fiecare data inserarea unui element se face adaugand un nod la ultimul nivel. Pentru nivelul 2 sunt doua noduri. La inserarea lor se va face cel mult o retrogradare (comparatie).

Pe ultimul exemplu de arbore, avem:

nivelul : 2 noduri 1 comparatie

nivelul : 4 noduri 2 comparatii

nivelul : 8 noduri 3 comparatii

nivelul i    : 2i-1 noduri i-1 comparatii

Considerand un arbore complet (nivel complet) T N = 2k - 1 T numarul total de comparatii pentru toate nodurile este T(n) de la nivelul 2 la nivelul k. Vom calcula:

Sa aratam:   

cu tehnica    . Asadar:

Rezulta:   

iar ,

din

Rezulta:   

----- ----- ----- ----- ----

termen dominant

Facandu-se majorari, rezulta complexitatea O(n log n).

Prezentam acum alta strategie de obtinere a heap_gen cu o complexitate mai buna:

Construim heap-ul de jos in sus (de la dreapta spre stanga). Cele mai multe noduri sunt la baza, doar nodurile din varf parcurg drumul cel mai lung.

Elementele V[i+1,N] indeplinesc conditia de structura a heap-ului:

j >i avem: V[j] > V[2*j] , daca 2*j N

V[j] > V[2*j +1] , daca 2*j + 1 N

Algoritmul consta in adaugarea elementului V[i] la structura heap-ului. El va fi retrogradat la baza heap-ului (prelucrare prin retrogradare):

retrogradare(V, N, i)

In aceasta situatie, vom avea:

heap_gen

Complexitatea acestei operatii

Fie un arbore complet cu n = 2k Cazul cel mai defavorabil este situatia in care la fiecare retrogradare se parcurg toate nivelele:

nivel k    : nu se fac operatii

nivel k-1    : 2k-2 noduri    o operatie de comparatie

nivel k-2    : 2k-3 noduri    2 operatii

nivel i    : 2i-1 noduri    k-i operatii

nivel : 2 noduri    k-2 operatii

nivel : 2 noduri    k-1 operatii

Se aduna, si rezulta:   

Tehnica de calcul este aceeasi:

Rezulta:   

termen dominant

Rezulta complexitatea este O(n). Comparand cu varianta anterioara, in aceasta varianta (cu heap-ul la baza) am castigat un ordin de complexitate. Rezulta, complexitatea algoritmului Heap_Sort este determinata de functiile remove ce nu pot fi aduse la mai putin de complexitate O(log n). Rezulta:

Heap_Sort = O(n) + O(n·log n)

----- ----- -----

termen ce determina complexitatea

Rezulta complexitatea alg. Heap_Sort = O(n·log n)



Document Info


Accesari: 3492
Apreciat: hand-up

Comenteaza documentul:

Nu esti inregistrat
Trebuie sa fii utilizator inregistrat pentru a putea comenta


Creaza cont nou

A fost util?

Daca documentul a fost util si crezi ca merita
sa adaugi un link catre el la tine in site


in pagina web a site-ului tau.




eCoduri.com - coduri postale, contabile, CAEN sau bancare

Politica de confidentialitate | Termenii si conditii de utilizare




Copyright © Contact (SCRIGROUP Int. 2024 )