10d. Gebalanceerde zoekbomen

2021-03-12
slides.com/jod/pt_10d

Docent: Jo Devriendt

Assistent: Ann Philips

Coördinator: Joost Vennekens

voornaam.achternaam@kuleuven.be

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

Analyse van
complete zoekboom

  • n = #nodes
  • Om element toe te voegen, te vinden of te verwijderen, loop je in het slechtste geval over de hoogte van de boom
    • #stappen = hoogte
    •  
    • hoogte
    • #stappen = O(log(n))
    • volgorde blijft behouden
  • Beter dan lineaire datastructuren waar een element vinden O(n) stappen kost

6

4

8

5

2

7

9

3

1

\leq \mathit{log}_{2}(n)+1
2^{\mathit{hoogte}-1} \leq n

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

Probleem: geen garantie dat zoekboom compleet is...

#define N 5

int main() {
  int waardes[N] = {0,1,2,3,4};
  printf("Bouw zoekboom\n");
  Node* root = NULL;
  for (int i = 0; i < N; ++i) {
    root = voegToe(root, waardes[i]);
  }
  print(root, 0);
  root = destroy(root);
}
$ ./a.out
Bouw zoekboom
                ->4 
            ->3 
        ->2 
    ->1 
->0

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

Tussenoplossing:
gebalanceerde zoekboom

  • Gebalanceerd: voor elke node, de linker- en rechtersubboom verschillen niet meer dan 1 in hoogte
  • Elke complete boom is gebalanceerd
  • Een gebalanceerde boom met n nodes heeft
    hoogte = O(log(n))

6

4

8

5

2

7

9

3

1

Verschillende hoogte linker- en rechterdeelboom

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

#define N 5

int main() {
  int waardes[N] = {0,1,2,3,4};
  printf("Bouw zoekboom\n");
  Node* root = NULL;
  for (int i = 0; i < N; ++i) {
    root = voegToe(root, waardes[i]);
  }
  print(root, 0);
  root = destroy(root);
}
$ ./a.out
Bouw zoekboom
                ->4 
            ->3 
        ->2 
    ->1 
->0

Probleem: geen garantie dat zoekboom gebalanceerd is...

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

balanceer

  1. Stockeer waarden gesorteerd in dynamische array
    • Bvb. mbv. Stack :)
    • Merk op: inorder loopt van klein naar groot door boom
  2. Creëer nieuwe boom recursief
    • neem middelste waarde voor huidige node
    • creëer linkerdeelboom met kleinere waarden
    • creëer rechterdeelboom met grotere waarden
Node* balanceer(Node* t);
void toStack(Node* t, Stack* s);
Node* maak(int waardes[], int lengte);

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

balanceer

6

4

8

2

7

9

3

1

maak

4

[1]

[6]

2

7

[3]

[8,9]

4

maak

[1,2,3]

[6,7,8,9]

toStack

[1,2,3,4,6,7,8,9]

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

balanceer

4

[1]

[6]

2

7

[3]

[8,9]

[]

[]

maak

4

2

7

3

1

6

8

9

maak

4

2

7

3

1

6

8

9

maak

4

2

7

[]

[]

[]

[]

[]

[]

[]

[9]

1

3

6

8

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

balanceer

void toStack(Node* t, Stack* s) {
  if (t == NULL) {
    return;
  }
  toStack(t->links, s);
  push(s, t->data);
  toStack(t->rechts, s);
}
Node* balanceer(Node* t) {
  Stack s = create();
  toStack(t, &s);
  t = destroy(t);
  t = maak(s.waardes, s.lengte);
  destroyStack(&s);
  return t;
}

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

balanceer

Node* maak(int waardes[], int lengte) {
  if (lengte == 0) {
    return NULL;
  }
  Node* p = (Node*) malloc(sizeof(Node));
  int mid = lengte / 2;
  p->data = waardes[mid];
  p->links = maak(&waardes[0], mid);
  p->rechts = maak(&waardes[mid + 1], lengte - (mid + 1));
  return p;
}
Node* balanceer(Node* t) {
  Stack s = create();
  toStack(t, &s);
  t = destroy(t);
  t = maak(s.waardes, s.lengte);
  destroyStack(&s);
  return t;
}

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

#define N 11

int main() {
  int waardes[N] = {5,8,4,10,3,1,6,7,9,0,2};
  printf("Bouw zoekboom\n");
  Node* root = NULL;
  for (int i = 0; i < N; ++i) {
    root = voegToe(root, waardes[i]);
  }
  print(root, 0);
  printf("Balanceer zoekboom\n");
  root = balanceer(root);
  print(root, 0);
  root = destroy(root);
}
Bouw zoekboom
        ->10
            ->9 
    ->8 
            ->7 
        ->6 
->5 
    ->4 
        ->3 
                ->2
            ->1 
                ->0
Balanceer zoekboom
        ->10
            ->9 
    ->8 
        ->7 
            ->6 
->5 
        ->4 
            ->3 
    ->2 
        ->1 
            ->0

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

Hoe zoekboom gebalanceerd houden?

  • Een verwijder / voegToe operatie kan de zoekboom uit balans brengen
    • balanceer(...) is O(n)
    • telkens balanceer oproepen is te kostelijk
  • Zelf-balancerende zoekbomen
    • AVR-bomen, rood-zwart bomen, ...
    • verwijder / voegToe aangepast zodat de boom in balans blijft, in O(log(n))
    • details brengen ons te ver :)

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

Oefening

  • Schrijf een procedure maakCompleet die van een willekeurige zoekboom een complete zoekboom maakt.
Node* maakCompleet(Node*);

Programmeertechnieken [B-KUL-YI0855]

De Nayer, IIW, E-ICT, 2Ba + schakel, 2020-2021

Samenvatting

  • Gebalanceerde zoekbomen laten toe om in O(log(n)) op te zoeken, toe te voegen, te verwijderen
  • Zelf-balancerende bomen zorgen dat zoekboom gebalanceerd blijft tijdens manipulatie

10d. Gebalanceerde zoekbomen

By Jo Devriendt

10d. Gebalanceerde zoekbomen

  • 603