Contactmoment
10 mei

slides.com/jod/pt_mei_10

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

Contactmoment 10 mei

Programmeertechnieken [B-KUL-YI0855]

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

Onderwerp:

Het examen

Modaliteiten

Programmeertechnieken [B-KUL-YI0855]

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

  • 14 juni
  • 8:45 - 11:45
  • A002 (A004)
  • Examen staat op 20 punten en wordt herschaald naar 10 voor het eindcijfer.

Disclaimer

Programmeertechnieken [B-KUL-YI0855]

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

De volgende voorbeeldvragen zijn ter indicatie, er is geen garantie dat een gelijkaardige vraag zal voorkomen op het examen, dat de uiteindelijke puntenverdeling exact zal overeenkomen met de gegeven voorbeelden, of dat er niet ook volledig andere vragen in het examen zullen zitten.

Theorie

Programmeertechnieken [B-KUL-YI0855]

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

  • Wat betekent pass-by-value? (1/20)
  • Beschrijf de call stack. Welke data bevindt zich in de call stack? Welke data bevindt zich niet in de call stack, maar in de heap? Wat is een stack smash? (2/20)
  • Wat is procedureel programmeren? Geef o.a. een procedurele programmeertaal. (1/20)
  • Wat is een dangling pointer? (1/20)
  • Hoe werkt backtracking? (2/20)
  • Wat is rubber duck debugging? (1/20)
  • Beschrijf in je eigen woorden de Church-Turing-hypothese. (1/20)

Oefeningen

Programmeertechnieken [B-KUL-YI0855]

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

#include <stdio.h>

int main() {
  unsigned int x = 3;
  unsigned int* y = &x;
  unsigned int* z[1] = {y};
  x = *(&y[-3]+x) << **z;
  printf("x: %d\n",x);
  return 0;
}

Wat is de output van volgend programma? (1/20)

#include <stdio.h>

int main() {
  int dagen_in_maand = 29;
  switch(dagen_in_maand) {
    case 31 :
    case 30 :
      printf("normale maand");
      break;
    case 29 :
      printf("schrikkeljaar-");
    case 28 :
      printf("februari");
      break;
    default :
      printf("onbestaande maand");
  }
  return 0;
}

Oefening (3/20)

Programmeertechnieken [B-KUL-YI0855]

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

De tribonacci-functie is gedefinieerd als volgt:

trib(n) = \begin{cases} 0 & \text{als } n = 0 \\ 0 & \text{als } n = 1 \\ 1 & \text{als } n = 2 \\ trib(n-1)+fib(n-2)+fib(n-3) & \text{als n>2} \end{cases}

De tribonacci-reeks is bijgevolg 0, 0, 1, 1, 2, 4, 7, 13, 24, ...

Schrijf een recursief C-programma dat het n-de tribonaccigetal berekent. Gebruikt je programma staartrecursie?

Oefening+theorie (1/20)

Programmeertechnieken [B-KUL-YI0855]

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

Jij en je team krijgen een nieuwe opdracht: bouw een robot-bij die autonoom rondvliegt van bloem naar bloem, en op die manier de bloemen bestuift. De robot-bij is klein en heeft maar een kleine batterij. Daarnaast is het de bedoeling een zwerm robot-bijen te bouwen, dus de hardware mag niet te duur zijn. Het is jouw taak om het programma te schrijven dat de richting berekent waarin de robot-bij moet vliegen, en je hebt de vrije keuze over de programmeertaal. Met welk programmeerparadigma zal je gekozen programmeertaal werken? Waarom is dit een goede keuze?

Oefening+theorie (4/20)

Programmeertechnieken [B-KUL-YI0855]

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

Gegeven is de volgende zoekboom voor de getallen {0,1,2,3,4}, en de bijbehorende C-struct.

  • Is deze boom gebalanceerd?
  • Geef een C-procedure die een getal verwijdert uit de zoekboom, bijvoorbeeld met prototype "Node* verwijder(Node* t, int x)"
  • Pas dit algoritme toe door eerst 3 te verwijderen, en dan 2. Teken de zoekboom na elke verwijdering.

3

1

4

0

2

typedef struct node{
  int data;
  struct node* links;
  struct node* rechts;
} Node

Lange oefening (5/20)

Programmeertechnieken [B-KUL-YI0855]

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

  • Gegeven: een dubbelgelinkte lijst waarbij het eerste element aangewezen wordt door de variabele top. De informatie in een element van de lijst bevat een letter en een geheel getal.
  • Schrijf een C-struct voor een element van deze lijst
  • Schrijf een C-functie herschik, met één argument (top): de functie herschikt de pointers zodanig dat elk even element voor het oneven element komt. Met andere woorden, het 2e element wordt het 1e en omgekeerd, het 4e element het 3e en omgekeerd, enz. De teruggeefwaarde van herschik is de pointer naar het nieuwe eerste element. Merk op: indien het aantal elementen oneven is, moet het laatste element toch juist aan het nieuwe voorgaande element gekoppeld worden.
  • Bijvoorbeeld, als de inputlijst bestaat uit [A, B, C, D, E], dan geeft de functie een pointer terug naar de herschikking [B, A, D, C, E].

Lange oefening (6/20)

Programmeertechnieken [B-KUL-YI0855]

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

Een groot land wil al z'n steden verbinden met de nieuwste soort internetkabel: "ultrakabel". Na een tijdje is tussen sommige steden al een ultrakabel gelegd, tussen anderen niet. Aangezien ultrakabel nogal duur is, wordt beslist dat het voldoende is als steden indirect met elkaar verbonden zijn: als er een ultrakabel ligt tussen A en B, en ook tussen B en C, dan is A indirect verbonden met C, en hoeft er tussen A en C geen nieuwe ultrakabel gelegd te worden. De vraag is nu, gegeven de reeds gelegde ultrakabels, moeten er nog kabels gelegd worden? Met andere woorden, zijn alle steden al (indirect) met elkaar verbonden?

Ontwerp een C-programma dat een antwoord geeft op deze vraag. Probeer dat programma zo efficiënt mogelijk te maken in het geval er een zeer groot aantal steden zijn in het land.

Programmeertechnieken [B-KUL-YI0855]

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

 Als input krijgt het programma twee arrays van strings, beiden met lengte n, genaamd van en naar. Voor elke i van 0 tot n geldt dat er al een ultrakabel ligt tussen steden van[i] en naar[i]. Elke stad is hoogstens met 3 andere steden verbonden, er is hoogstens één ultrakabel tussen elke twee steden, de richting van de ultrakabel maakt niet uit, en geen enkele stad heeft een ultrakabel naar zichzelf.

Als output geeft het programma het getal 1 terug indien alle steden (indirect) verbonden zijn, en 0 indien dit niet zo is.

Beschrijf je programma. Geef onder andere het prototype van de procedures die je gebruikt, wat die procedures doen, en welke procedures elke procedure oproept. Geef ook aan welke datastructuren je gebruikt. Geef tenslotte een inschatting van het aantal stappen dat je programma nodig heeft om het antwoord te berekenen, in functie van het aantal steden. Denk je dat er een programma bestaat dat significant minder stappen nodig heeft?

Programmeertechnieken [B-KUL-YI0855]

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

Beschrijving:

Om te checken of alle steden verbonden zijn, zal het programma eerst een hashtabel "rechtstreeks" maken, met als keys alle steden, en met als waardes telkens de maximum 3 steden waarmee een key rechtstreeks verbonden is. Deze hashtabel wordt aangemaakt door op de inputarrays te overlopen en telkens de stad naar[i] toe te voegen aan de waarde voor key van[i], en vice versa, van[i] als waarde voor naar[i].

Daarna kiest het programma een willekeurige stad "teVerwijderen", bijvoorbeeld van[0], kopieert het de rechtstreeks verbonden steden in een tijdelijke variabele, verwijdert het de key van "teVerwijderen" uit "rechtstreeks", en herhalen we dezelfde operatie op de rechtstreeks verbonden steden. Dit is dus een recursieve procedure. Als een stad geen key (meer) heeft in "rechtstreeks", stopt de recursie.

Potentieel antwoord

Programmeertechnieken [B-KUL-YI0855]

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

Als na het recursief verwijderen de hashtabel leeg is, zijn alle steden inderdaad verbonden met de willekeurig gekozen stad, en dus met elkaar. Als er nog keys over zijn, dan stellen die steden voor die niet verbonden zijn met de willekeurige stad, en dus zijn niet alle steden verbonden met elkaar.

// procedure die gegeven de input antwoord of alle steden verbonden zijn
int isVolledigVerbonden(char** van, char** naar, int n)
// roept "initialiseerRechtstreeks" en "verwijderRecursief" op

// procedure die de hashtabel initialiseert op basis van de input
void initialiseerRechtstreeks(HashTabel* rechtstreeks, char** van, char** naar, int n)
// roept "voegKabelToe" op

// voegt in de hashtabel "naar" toe aan waarde voor de key "van"
void voegKabelToe(HashTabel* rechtstreeks, char* van, char* naar)
// roept enkel standaardprocedures voor een hashtabel op

// verwijdert teVerwijderen en de rechtstreeks verbonden steden van teVerwijderen
void verwijderRecursief(HashTabel* rechtstreeks, char* teVerwijderen)
// roept enkel standaardprocedures voor een hashtabel op

Prototypes van de procedures:

Programmeertechnieken [B-KUL-YI0855]

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

Efficiëntie-analyse:

Laat n het aantal steden in het land zijn.

Om de hashtabel "rechtstreeks" te construeren itereert het algoritme over de input, en past het in elke iteratie twee keer de hashtabel aan. Aangezien elke stad met hoogstens 3 andere verbonden is, gaat het algoritme dus hoogstens 6*n aanpassingen doen aan de hashtabel tijdens de constructie van "rechtstreeks", wat overeenkomt met O(n).

De recursieve verwijderprocedure doet niets indien een stad geen key (meer) heeft in "rechtstreeks", en anders verwijdert het een key vooraleer de recursie verder te zetten. Het aantal recursieve oproepen is dus begrensd door het initiële aantal keys in de hashtabel, wat exact het aantal steden n is. Elke recursieve oproep verwijdert hoogstens één key, en start hoogstens 3 nieuwe recursieve oproepen (voor elke verbonden stad). Het aantal stappen in één recursieve oproep is dus onafhankelijk van n. Bijgevolg schatten we ook het aantal stappen voor het recursieve verwijderen als O(n).

Programmeertechnieken [B-KUL-YI0855]

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

Efficiëntie-analyse (vervolg):

Checken of een hashtabel leeg is, is ook onafhankelijk van het aantal steden.

Als we veronderstellen dat de typische operaties op een hashtabel (opzoeken van een key, toevoegen van een key-waarde, verwijderen van een key) zeer efficiënt zijn, ongeacht het aantal steden, dan groeit het aantal stappen in ons algoritme lineair met het aantal steden, m.a.w., het algoritme heeft O(n) stappen nodig. Het lijkt aannemelijk dat elk algoritme dat checkt of n steden verbonden zijn, toch minstens alle steden moet overlopen (bvb. om de data in te lezen), dus het zal moeilijk worden om significant minder stappen te gebruiken.

Programmeertechnieken [B-KUL-YI0855]

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

  • Er zijn andere antwoorden mogelijk op deze vraag, die even goed zijn.
    • Bvb. een niet-recursieve versie met een stack om bij te houden welke steden nog behandeld moeten worden
  • Een correct traag programma is altijd beter dan een incorrect snel programma. In het eerste geval, leg helder uit waar het programma traag is, en hoe het misschien sneller zou kunnen.
  • De bedoeling van deze vraag is niet om code te schrijven voor een volledig werkend bug-vrij C-programma, maar om inzicht te tonen in datastructuren en algoritmiek.
  • Ter info: een volledig werkend programma voor deze vraag kan je vinden op pastebin.com/1xRqsGER . Het is een interessant voorbeeld van een mix van hashtabellen en recursie.

Nabespreking