10c. Zoekbomen

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

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

Zoekboom

  • Datastructuur in de vorm van een binaire boom om gegevens gesorteerd te stockeren
  • Voor elke node:
    • Linkse descendants bevatten strikt kleinere waarden
    • Rechtse descendants bevatten strikt grotere waarden
5
4
2
1
8
typedef struct node {
  int data;
  struct node* links;
  struct node* rechts;
} Node;

Programmeertechnieken [B-KUL-YI0855]

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

destroy

Node* destroy(Node* t) {
  if (t != NULL) {
    destroy(t->links);
    destroy(t->rechts);
    free(t);
  }
  return NULL;
}
typedef struct node {
  int data;
  struct node* links;
  struct node* rechts;
} Node;

Programmeertechnieken [B-KUL-YI0855]

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

voegToe

Node* voegToe(Node* t, int x) {
  if (t == NULL) {
    Node* nieuw = (Node*) malloc(sizeof(Node));
    nieuw->data = x;
    nieuw->links = NULL;
    nieuw->rechts = NULL;
    return nieuw;
  }
  if (x < t->data) {
    t->links = voegToe(t->links, x);
  } else if (x > t->data) {
    t->rechts = voegToe(t->rechts, x);
  }
  return t;
}
typedef struct node{
  int data;
  struct node* links;
  struct node* rechts;
} Node

2

1

4

Voeg 3 toe aan deze boom:

Programmeertechnieken [B-KUL-YI0855]

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

voegToe

Node* voegToe(Node* t, int x) {
  if (t == NULL) {
    Node* nieuw = (Node*) malloc(sizeof(Node));
    nieuw->data = x;
    nieuw->links = NULL;
    nieuw->rechts = NULL;
    return nieuw;
  }
  if (x < t->data) {
    t->links = voegToe(t->links, x);
  } else if (x > t->data) {
    t->rechts = voegToe(t->rechts, x);
  }
  return t;
}
typedef struct node{
  int data;
  struct node* links;
  struct node* rechts;
} Node

2

1

4

Voeg 3 toe aan deze boom:

voegToe(&2,3)

Programmeertechnieken [B-KUL-YI0855]

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

voegToe

Node* voegToe(Node* t, int x) {
  if (t == NULL) {
    Node* nieuw = (Node*) malloc(sizeof(Node));
    nieuw->data = x;
    nieuw->links = NULL;
    nieuw->rechts = NULL;
    return nieuw;
  }
  if (x < t->data) {
    t->links = voegToe(t->links, x);
  } else if (x > t->data) {
    t->rechts = voegToe(t->rechts, x);
  }
  return t;
}
typedef struct node{
  int data;
  struct node* links;
  struct node* rechts;
} Node

2

1

4

Voeg 3 toe aan deze boom:

voegToe(&2,3)
voegToe(&4,3)

Programmeertechnieken [B-KUL-YI0855]

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

voegToe

Node* voegToe(Node* t, int x) {
  if (t == NULL) {
    Node* nieuw = (Node*) malloc(sizeof(Node));
    nieuw->data = x;
    nieuw->links = NULL;
    nieuw->rechts = NULL;
    return nieuw;
  }
  if (x < t->data) {
    t->links = voegToe(t->links, x);
  } else if (x > t->data) {
    t->rechts = voegToe(t->rechts, x);
  }
  return t;
}
typedef struct node{
  int data;
  struct node* links;
  struct node* rechts;
} Node

2

1

4

Voeg 3 toe aan deze boom:

voegToe(&2,3)
voegToe(&4,3)
voegToe(NULL,3)

3

Programmeertechnieken [B-KUL-YI0855]

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

voegToe

Node* voegToe(Node* t, int x) {
  if (t == NULL) {
    Node* nieuw = (Node*) malloc(sizeof(Node));
    nieuw->data = x;
    nieuw->links = NULL;
    nieuw->rechts = NULL;
    return nieuw;
  }
  if (x < t->data) {
    t->links = voegToe(t->links, x);
  } else if (x > t->data) {
    t->rechts = voegToe(t->rechts, x);
  }
  return t;
}
typedef struct node{
  int data;
  struct node* links;
  struct node* rechts;
} Node

2

1

4

Voeg 3 toe aan deze boom:

voegToe(&2,3)
voegToe(&4,3)

3

Programmeertechnieken [B-KUL-YI0855]

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

voegToe

Node* voegToe(Node* t, int x) {
  if (t == NULL) {
    Node* nieuw = (Node*) malloc(sizeof(Node));
    nieuw->data = x;
    nieuw->links = NULL;
    nieuw->rechts = NULL;
    return nieuw;
  }
  if (x < t->data) {
    t->links = voegToe(t->links, x);
  } else if (x > t->data) {
    t->rechts = voegToe(t->rechts, x);
  }
  return t;
}
typedef struct node{
  int data;
  struct node* links;
  struct node* rechts;
} Node

2

1

4

Voeg 3 toe aan deze boom:

voegToe(&2,3)

3

Programmeertechnieken [B-KUL-YI0855]

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

voegToe

Node* voegToe(Node* t, int x) {
  if (t == NULL) {
    Node* nieuw = (Node*) malloc(sizeof(Node));
    nieuw->data = x;
    nieuw->links = NULL;
    nieuw->rechts = NULL;
    return nieuw;
  }
  if (x < t->data) {
    t->links = voegToe(t->links, x);
  } else if (x > t->data) {
    t->rechts = voegToe(t->rechts, x);
  }
  return t;
}
typedef struct node{
  int data;
  struct node* links;
  struct node* rechts;
} Node

2

1

4

Voeg 3 toe aan deze boom:

3

Programmeertechnieken [B-KUL-YI0855]

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

voegToe

Node* voegToe(Node* t, int x) {
  if (t == NULL) {
    Node* nieuw = (Node*) malloc(sizeof(Node));
    nieuw->data = x;
    nieuw->links = NULL;
    nieuw->rechts = NULL;
    return nieuw;
  }
  if (x < t->data) {
    t->links = voegToe(t->links, x);
  } else if (x > t->data) {
    t->rechts = voegToe(t->rechts, x);
  }
  return t;
}

Werkt meteen ook om een initiële boom aan te maken ("create"):

Node* root = voegToe(NULL,...);
typedef struct node{
  int data;
  struct node* links;
  struct node* rechts;
} Node

Programmeertechnieken [B-KUL-YI0855]

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

print & main

void print(Node* t, int level) {
  if (t == NULL) {
    return;
  }
  print(t->rechts, level + 1);
  for (int i = 0; i < 4 * level; ++i) {
    printf(" ");
  }
  printf("->");
  printf("%-2d\n", t->data);
  print(t->links, level + 1);
}

#define N 11

int main() {
  int waardes[N] = {5,8,4,10,3,1,6,7,9,0,2};
  Node* root = NULL;
  for (int i = 0; i < N; ++i) {
    root = voegToe(root, waardes[i]);
  }
  print(root, 0);
  root = destroy(root);
}
$./a.out
        ->10
            ->9 
    ->8 
            ->7 
        ->6 
->5 
    ->4 
        ->3 
                ->2
            ->1 
                ->0

Programmeertechnieken [B-KUL-YI0855]

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

verwijder

Complex: zoekboom moet gesorteerd blijven

  1. x zit niet in de boom: doe niks
  2. node met x heeft minstens 1 NULL kind: verwijder node met x, ander kind wordt kind van ouder
  3. node met x heeft geen NULL kinderen: zoek meest rechtse node van linker deelboom
    • meest rechtse node bestaat: waarde van die node wordt waarde van huidige node, verwijder die node, maar behoud diens linkerkind
    • meest rechtse node bestaat niet: rechterkind (==NULL) van linkerkind vervangen door rechterkind van huidige node, verwijder huidige node
Node* verwijder(Node* t, int x);

Programmeertechnieken [B-KUL-YI0855]

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

verwijder

2. node met x heeft minstens 1 NULL kind: verwijder node met x, ander kind wordt kind van ouder

Node* verwijder(Node* t, int x);

2

1

4

3

Verwijder 4:

Programmeertechnieken [B-KUL-YI0855]

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

verwijder

2. node met x heeft minstens 1 NULL kind: verwijder node met x, ander kind wordt kind van ouder

Node* verwijder(Node* t, int x);

2

1

3

Verwijder 4:

Programmeertechnieken [B-KUL-YI0855]

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

verwijder

2. node met x heeft minstens 1 NULL kind: verwijder node met x, ander kind wordt kind van ouder

Node* verwijder(Node* t, int x);

2

1

3

Verwijder 4:

Programmeertechnieken [B-KUL-YI0855]

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

verwijder

3. node met x heeft geen NULL kinderen: zoek meest rechtse node van linker deelboom

  • meest rechtse node bestaat: waarde van die node wordt waarde van huidige node, verwijder die node, maar behoud diens linkerkind
Node* verwijder(Node* t, int x);

4

1

5

2

Verwijder 4:

3

Programmeertechnieken [B-KUL-YI0855]

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

verwijder

Node* verwijder(Node* t, int x);

3

3. node met x heeft geen NULL kinderen: zoek meest rechtse node van linker deelboom

  • meest rechtse node bestaat: waarde van die node wordt waarde van huidige node, verwijder die node, maar behoud diens linkerkind

Verwijder 4:

4

1

5

2

Programmeertechnieken [B-KUL-YI0855]

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

verwijder

Node* verwijder(Node* t, int x);

3

1

5

3

3. node met x heeft geen NULL kinderen: zoek meest rechtse node van linker deelboom

  • meest rechtse node bestaat: waarde van die node wordt waarde van huidige node, verwijder die node, maar behoud diens linkerkind

Verwijder 4:

2

Programmeertechnieken [B-KUL-YI0855]

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

verwijder

Node* verwijder(Node* t, int x);

3

1

5

3. node met x heeft geen NULL kinderen: zoek meest rechtse node van linker deelboom

  • meest rechtse node bestaat: waarde van die node wordt waarde van huidige node, verwijder die node, maar behoud diens linkerkind

Verwijder 4:

2

Programmeertechnieken [B-KUL-YI0855]

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

verwijder

Node* verwijder(Node* t, int x);

3

1

5

3. node met x heeft geen NULL kinderen: zoek meest rechtse node van linker deelboom

  • meest rechtse node bestaat: waarde van die node wordt waarde van huidige node, verwijder die node, maar behoud diens linkerkind

Verwijder 4:

2

Programmeertechnieken [B-KUL-YI0855]

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

verwijder

3. node met x heeft geen NULL kinderen: zoek meest rechtse node van linker deelboom

  • meest rechtse node bestaat niet: rechterkind (==NULL) van linkerkind vervangen door rechterkind van huidige node, verwijder huidige node
Node* verwijder(Node* t, int x);

Verwijder 2:

2

1

4

0

Programmeertechnieken [B-KUL-YI0855]

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

verwijder

Node* verwijder(Node* t, int x);

2

1

4

0

3. node met x heeft geen NULL kinderen: zoek meest rechtse node van linker deelboom

  • meest rechtse node bestaat niet: rechterkind (==NULL) van linkerkind vervangen door rechterkind van huidige node, verwijder huidige node

Verwijder 2:

Programmeertechnieken [B-KUL-YI0855]

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

verwijder

Node* verwijder(Node* t, int x);

2

1

4

0

3. node met x heeft geen NULL kinderen: zoek meest rechtse node van linker deelboom

  • meest rechtse node bestaat niet: rechterkind (==NULL) van linkerkind vervangen door rechterkind van huidige node, verwijder huidige node

Verwijder 2:

Programmeertechnieken [B-KUL-YI0855]

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

verwijder

Node* verwijder(Node* t, int x);

1

4

0

3. node met x heeft geen NULL kinderen: zoek meest rechtse node van linker deelboom

  • meest rechtse node bestaat niet: rechterkind (==NULL) van linkerkind vervangen door rechterkind van huidige node, verwijder huidige node

Verwijder 2:

Programmeertechnieken [B-KUL-YI0855]

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

Node* verwijder(Node* t, int x) {
  if (t == NULL) {
    // x komt blijkbaar niet voor
    return NULL;
  }
  if (x < t->data) {
    t->links = verwijder(t->links, x);
    return t;
  } else if (x > t->data) {
    t->rechts = verwijder(t->rechts, x);
    return t;
  }
  // x == t->data
  if (t->links == NULL) {
    Node* p = t->rechts;
    free(t);
    return p;
  } else if (t->rechts == NULL) {
    Node* p = t->links;
    free(t);
    return p;
  }
  // vervolg: twee niet-NULL deelbomen
  // ...

x komt niet voor

Zoek verder

Minstens 1 NULL kind

Programmeertechnieken [B-KUL-YI0855]

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

Node* verwijder(Node* t, int x) {
  // vervolg: twee niet-NULL deelbomen
  Node* p = t->links;
  Node* q = t;
  while (p->rechts != NULL) {
    q = p;
    p = p->rechts;
  }
  if (q != t) { // wel meest rechtse node
    q->rechts = p->links;
    t->data = p->data;
    free(p);
    return t;
  } else { // geen meest rechtse node
    p->rechts = t->rechts;
    free(t);
    return p;
  }
}

Vind meest rechtse node in linkerdeelboom

Behoud linkerkind

Kopieer waarde

Verwijder meest rechtse

Verwijder huidige node

Vervang NULL-kleinkind

Geef linkerkind terug

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("Verwijder 5 & 8\n");
  root = verwijder(root, 5);
  root = verwijder(root, 8);
  print(root, 0);
  root = destroy(root);
}
Bouw zoekboom
        ->10
            ->9 
    ->8 
            ->7 
        ->6 
->5 
    ->4 
        ->3 
                ->2
            ->1 
                ->0
Verwijder 5 & 8
        ->10
            ->9 
    ->7 
        ->6 
->4 
    ->3 
            ->2 
        ->1 
            ->0 

Programmeertechnieken [B-KUL-YI0855]

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

Oefeningen

Schrijf procedures voor

  • bevat: test of een waarde in de boom zit
  • max: geeft de grootste waarde in de boom terug
int bevat(Node* t, int x);
int max(Node* t);

Programmeertechnieken [B-KUL-YI0855]

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

Samenvatting

  • Zoekbomen zijn een niet-lineaire datastructuur voor gesorteerde data
    • links zitten kleinere elementen
    • rechts grotere
  • Manipulatie van zoekboom vereist enigszins complexe algoritmes