9b. Gelinkte lijsten

2021-03-04
slides.com/jod/pt_9b

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

Centraal idee

  • Gebruik aaneengelinkte nodes
  • Elke node houdt één element bij, en een pointer bij naar de node met het  volgende element
  • De laatste node heeft NULL als volgende
  • Speciale pointer kop wijst naar eerste node
typedef struct Node_tag {
  char c;
  struct Node_tag* volgende;
} Node;

Bvb. sequentie ['p', 'e', 't']

'p'

volgende

'e'

volgende

't'

volgende

NULL

kop

Programmeertechnieken [B-KUL-YI0855]

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

Element toevoegen (vooraan)

Node* voegToe(Node* kop, char element){
  Node* nieuw = (Node*) malloc(sizeof(Node));
  nieuw->c = element;
  nieuw->volgende = kop;
  return nieuw;
}

int main(){
  char* s = "pet";
  Node* kop = NULL;
  for(int i=2; i>=0; --i){
    kop = voegToe(kop, s[i]);
  }
  
  // ...
}

kop

NULL

Programmeertechnieken [B-KUL-YI0855]

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

Node* voegToe(Node* kop, char element){
  Node* nieuw = (Node*) malloc(sizeof(Node));
  nieuw->c = element;
  nieuw->volgende = kop;
  return nieuw;
}

int main(){
  char* s = "pet";
  Node* kop = NULL;
  for(int i=2; i>=0; --i){
    kop = voegToe(kop, s[i]);
  }
  
  // ...
}

kop

NULL

't'

volgende

NULL

Element toevoegen (vooraan)

Programmeertechnieken [B-KUL-YI0855]

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

Node* voegToe(Node* kop, char element){
  Node* nieuw = (Node*) malloc(sizeof(Node));
  nieuw->c = element;
  nieuw->volgende = kop;
  return nieuw;
}

int main(){
  char* s = "pet";
  Node* kop = NULL;
  for(int i=2; i>=0; --i){
    kop = voegToe(kop, s[i]);
  }
  
  // ...
}

kop

NULL

't'

volgende

NULL

'e'

volgende

Element toevoegen (vooraan)

Programmeertechnieken [B-KUL-YI0855]

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

Node* voegToe(Node* kop, char element){
  Node* nieuw = (Node*) malloc(sizeof(Node));
  nieuw->c = element;
  nieuw->volgende = kop;
  return nieuw;
}

int main(){
  char* s = "pet";
  Node* kop = NULL;
  for(int i=2; i>=0; --i){
    kop = voegToe(kop, s[i]);
  }
  
  // ...
}

kop

NULL

't'

volgende

NULL

'e'

volgende

'p'

volgende

Element toevoegen (vooraan)

Programmeertechnieken [B-KUL-YI0855]

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

Vrijgeven

kop

?

'e'

volgende

't'

volgende

NULL

'p'

volgende

tmp

Node* geefVrij(Node* kop){
  while(kop!=NULL){
    Node* tmp = kop->volgende;
    free(kop);
    kop = tmp;
  }
  return NULL;
}

int main(){
  // ...
  kop = geefVrij(kop);
}

Programmeertechnieken [B-KUL-YI0855]

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

Vrijgeven

kop

'e'

volgende

NULL

't'

volgende

NULL

tmp

Node* geefVrij(Node* kop){
  while(kop!=NULL){
    Node* tmp = kop->volgende;
    free(kop);
    kop = tmp;
  }
  return NULL;
}

int main(){
  // ...
  kop = geefVrij(kop);
}

Programmeertechnieken [B-KUL-YI0855]

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

Vrijgeven

kop

'e'

volgende

NULL

't'

volgende

NULL

tmp

Node* geefVrij(Node* kop){
  while(kop!=NULL){
    Node* tmp = kop->volgende;
    free(kop);
    kop = tmp;
  }
  return NULL;
}

int main(){
  // ...
  kop = geefVrij(kop);
}

Programmeertechnieken [B-KUL-YI0855]

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

Vrijgeven

kop

't'

volgende

NULL

tmp

Node* geefVrij(Node* kop){
  while(kop!=NULL){
    Node* tmp = kop->volgende;
    free(kop);
    kop = tmp;
  }
  return NULL;
}

int main(){
  // ...
  kop = geefVrij(kop);
}

Programmeertechnieken [B-KUL-YI0855]

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

Vrijgeven

kop

't'

volgende

NULL

tmp

Node* geefVrij(Node* kop){
  while(kop!=NULL){
    Node* tmp = kop->volgende;
    free(kop);
    kop = tmp;
  }
  return NULL;
}

int main(){
  // ...
  kop = geefVrij(kop);
}

Programmeertechnieken [B-KUL-YI0855]

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

Vrijgeven

NULL

tmp

kop

Node* geefVrij(Node* kop){
  while(kop!=NULL){
    Node* tmp = kop->volgende;
    free(kop);
    kop = tmp;
  }
  return NULL;
}

int main(){
  // ...
  kop = geefVrij(kop);
}

Programmeertechnieken [B-KUL-YI0855]

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

Voorbeeld main

int main(){
  char* s = "pet";
  Node* kop = NULL;
  for(int i=2; i>=0; --i){
    kop = voegToe(kop, s[i]);
  }
  
  Node* tmp = kop;
  while(tmp!=NULL){
    printf("tmp->c: %c\n",tmp->c);
    tmp = tmp->volgende;
  }
  
  kop = geefVrij(kop);
}
$ ./a.out
tmp->c: p
tmp->c: e
tmp->c: t

Programmeertechnieken [B-KUL-YI0855]

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

Invoegen

void voegIn(Node* oud, Node* nieuw){
  nieuw->volgende = oud->volgende;
  oud->volgende = nieuw;
}

kop

'e'

volgende

't'

volgende

NULL

NULL

'p'

volgende

Programmeertechnieken [B-KUL-YI0855]

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

Invoegen

void voegIn(Node* oud, Node* nieuw){
  nieuw->volgend = oud->volgend;
  oud->volgend = nieuw;
}

kop

'e'

volgende

't'

volgende

NULL

'p'

volgende

Programmeertechnieken [B-KUL-YI0855]

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

Invoegen

void voegIn(Node* oud, Node* nieuw){
  nieuw->volgend = oud->volgend;
  oud->volgend = nieuw;
}

kop

'e'

volgende

't'

volgende

NULL

'p'

volgende

Maar twee operaties, onafhankelijk van lengte van lijst

Programmeertechnieken [B-KUL-YI0855]

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

Verwijderen

kop

NULL

't'

volgende

NULL

'e'

volgende

'p'

volgende

n
teVerwijderen
void verwijderVolgende(Node* n){
  if(n==NULL || n->volgende==NULL){
    return; // geen volgende
  }else{
    Node* teVerwijderen = n->volgende;
    n->volgende = teVerwijderen->volgende;
    free(teVerwijderen);
  }
}

Programmeertechnieken [B-KUL-YI0855]

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

Verwijderen

kop

NULL

't'

volgende

NULL

'e'

volgende

'p'

volgende

teVerwijderen
void verwijderVolgende(Node* n){
  if(n==NULL || n->volgende==NULL){
    return; // geen volgende
  }else{
    Node* teVerwijderen = n->volgende;
    n->volgende = teVerwijderen->volgende;
    free(teVerwijderen);
  }
}

Programmeertechnieken [B-KUL-YI0855]

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

Verwijderen

kop

NULL

't'

volgende

NULL

'p'

volgende

teVerwijderen

Maar ~4 operaties, onafhankelijk van lengte van lijst

void verwijderVolgende(Node* n){
  if(n==NULL || n->volgende==NULL){
    return; // geen volgende
  }else{
    Node* teVerwijderen = n->volgende;
    n->volgende = teVerwijderen->volgende;
    free(teVerwijderen);
  }
}

Programmeertechnieken [B-KUL-YI0855]

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

Dubbelgelinkte lijst

  • Dubbelgelinkte lijst: ook pointer bij naar vorige node
  • Laat toe om in twee richtingen door lijst te lopen
typedef struct Node_tag{
  Data data;
  struct Node_tag* volgende;
  struct Node_tag* vorige;
} Node;

'p'

volgende

vorige

'e'

volgende

vorige

't'

volgende

vorige

NULL

NULL

kop

Programmeertechnieken [B-KUL-YI0855]

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

Circulaire lijst

  • Eerste en laatste element verwijzen naar elkaar
  • Geen vast begin- of eindpunt
  • Kan zowel enkelgelinkt als dubbelgelinkt
typedef struct Node_tag{
  Data data;
  struct Node_tag* volgende;
  struct Node_tag* vorige;
} Node;

'p'

volgende

vorige

'e'

volgende

vorige

't'

volgende

vorige

kop

Programmeertechnieken [B-KUL-YI0855]

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

Samenvoegen circulaire lijsten

'p'

volgende

vorige

'i'

volgende

vorige

'n'

volgende

vorige

kop2

'p'

volgende

vorige

'e'

volgende

vorige

't'

volgende

vorige

kop1

Programmeertechnieken [B-KUL-YI0855]

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

Samenvoegen circulaire lijsten

'p'

volgende

vorige

'i'

volgende

vorige

'n'

volgende

vorige

kop2

'p'

volgende

vorige

'e'

volgende

vorige

't'

volgende

vorige

kop1

Programmeertechnieken [B-KUL-YI0855]

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

Samenvoegen circulaire lijsten

void voegSamen(Node* kop1, Node* kop2){
  Node* begin1 = kop1;
  Node* eind1 = kop1->vorige;
  Node* begin2 = kop2;
  Node* eind2 = kop2->vorige;
  
  begin1->vorige = eind2;
  eind2->volgende = begin1;
  begin2->vorige = eind1;
  eind1->volgende = begin2;
}

Maar 8 operaties, onafhankelijk van lengte van lijst

Programmeertechnieken [B-KUL-YI0855]

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

Oefeningen

  • Schrijf een keerOm procedure die de volgorde van de nodes in een gelinkte lijst omkeert
  • Schrijf een swap procedure die twee nodes in een dubbel gelinkte lijst verwisselt van plaats
    • Uitdaging: schrijf een swap voor een enkel-gelinkte lijst
// richting omkeren
void keerOm(Node* kop);

// omwisselen
void swap(Node* eerste, Node* tweede);
  • Hoeveel stappen heb je nodig om een node met een bepaald element te vinden in de lijst?

Programmeertechnieken [B-KUL-YI0855]

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

Samenvatting

  • Gelinkte lijst bestaat uit aaneengelinkte nodes
  • Elementen maken deel uit van node
  • Toevoegen en verwijderen van elementen vereist constant aantal operaties
  • Aantal operaties om twee circulair dubbelgelinkte lijsten samen te voegen is constant

9b. Gelinkte lijst

By Jo Devriendt

9b. Gelinkte lijst

  • 504