1 Tentamen 21 januari 2008 uitleg
2 1. Algemene kennisvragen a)“Wat verstaan we onder de complexiteit van een algoritme?” –Cruciaal: wat gebeurt er met de executietijd van een programma in verhouding tot de toename van de invoer?
3 1. Algemene kennisvragen b)“Noem 3 soorten samenstellings- mechanismen voor algoritmen.” –Cruciaal: waar kunnen algoritmen uit samengesteld zijn? Dat konden zaken zijn als top-down verfijningen, functies & procedures, herhalingen, keuzes e.d.
4 1. Algemene kennisvragen c)“Drie begrippen die nauw aan elkaar gerelateerd zijn, zijn type, waarde en object. Beschrijf kort, maar zo nauwkeurig mogelijk wat de verschillen tussen deze begrippen zijn.” –Cruciaal: op de een of andere manier moest duidelijk gemaakt worden dat een ‘type’ staat voor een verzameling mogelijke waarden, een object een variabele of een constante kan zijn en dat ‘variabelen van een bepaald type’ een waarde kunnen hebben. (bijv. int getal = 3; )
5 1. Algemene kennisvragen d)“Geef aan wat het verschil is tussen call-by-value en call-by-reference. Is het ook mogelijk om objecten die constant zijn via call-by-reference door te geven? Zo ja, wat kan hiervan het nut zijn? Zo nee, waarom niet?” –Cruciaal: dat duidelijk gemaakt werd, dat bij call-by- value [een kopie van] de waarde van een object wordt meegegeven en bij call-by-reference het object zelf [via het geheugenadres] ter bewerking wordt aangeboden.
6 1. Algemene kennisvragen e)“Geef de belangrijkste verschillen aan tussen enerzijds ‘ struct ’ s en anderzijds ‘ rijen ’ ” –struct: verzameling van elementen van mogelijk verschillend type / rij: verzameling van element van hetzelfde type –struct: elementen worden gevonden middels naam / rij: elementen middels index
7 1. Algemene kennisvragen f)“Bij het zoeken van een element in een ongesorteerde rij moet je in het ergste geval de hele rij doorlopen. Nu kom je op het idee om de rij eerst te sorteren, en daarna te zoeken, omdat je weet dat je middels binair zoeken veel eerder kunt stoppen. Geef aan of dit wel of niet een goed idee is en motiveer je antwoord.” –Beste in-situ sorteeralgoritme heeft complexiteit O(n log n) –Binair zoeken heeft complexiteit O(log n) –Dus eerst sorteren, dan binair zoeken: O(n log n) + O(log n) = O (n log n) –Zoeken in ongeordende rij heeft complexiteit O(n) –Zoeken in ongeordende rij heeft betere complexiteit, dus het is een slecht idee. –Maar: als je vaker in dezelfde rij wilt gaan zoeken, dan kan het wel verstandig zijn omdat de kosten van sorteren na verloop van tijd wegvallen.
8 2. Structs en rijen Mogelijke uitwerking 2.a: typedef char Naam [15 ] ; const int Rijlengte = 3 ; struct Lid { int lidnr ; Naam naam ; int gebjaar ; char postcode [ 8 ] ; int huisnr ; } ; typedef Lid Ledenrij [ Rijlengte ] ; struct JaarIndexStruct { int gebjaar ; int recordnr ; } ; typedef JaarIndexStruct Indexrij [ Rijlengte ] ;
9 2. Structs en rijen (vervolg 1) Mogelijke uitwerking 2.b, deel 1: void voeg_toe ( Ledenrij lrij, Indexrij inrij, int& aantal, Lid lid ) { if ( aantal >= Rijlengte ) cout << "Rij zit vol na " << aantal << " toevoegingen!\n\n" ; else { lrij[aantal] = lid ; voeg_gebjaar_indexrecord_toe ( inrij, aantal, lid ) ; aantal++ ; } Zie voor uitwerking “voeg_gebjaar_indexrecord_toe(..)” de volgende sheet.
10 2. Structs en rijen (vervolg 2) Mogelijke uitwerking 2.b, deel 2: void voeg_gebjaar_indexrecord_toe ( Indexrij inrij, int aantal, Lid lid ) { // moet volgens insertie-methode gebeuren int positie = aantal ; // zoek invoeg-positie op: (van achter naar voren) if ( aantal > 0 ) { while ( positie > 0 && inrij[positie-1].gebjaar > lid.gebjaar ) { positie-- ; } for ( int i = aantal ; i >positie ; i-- ) inrij [ i ] = inrij [ i - 1 ] ; // 1 naar achter schuiven } // else : aantal, dus 'positie' staat op 0... => niks; houden zo // nu: op gevonden 'positie' indexrecord tussenvoegen: inrij[positie].gebjaar = lid.gebjaar ; inrij[positie].recordnr = aantal ; }
11 2. Structs en rijen (vervolg 3) Mogelijke uitwerking 2.c: void toon_leden_op_geboortejaars_volgorde ( Ledenrij lrij, Indexrij inrij, int aantal ) { cout << "Lidgegevens, naar toenemend geboortejaar:\n\n" << "Lidnr \tNaam \t\tJaar \tPostcode+Huisnr:\n" ; for ( int inrijpos = 0; inrijpos < aantal ; inrijpos++ ) { const Lid dit_lid = lrij[inrij[inrijpos].recordnr] ;// verwijzing in rij! cout << dit_lid.lidnr << "\t" << dit_lid.naam << "\t" << dit_lid.gebjaar << "\t" << dit_lid.postcode << "\t" << dit_lid.huisnr << endl ; /* equivalent (zonder aparte ‘dit_lid’-declaratie: cout << lrij[inrij[inrijpos].recordnr].lidnr << "\t" << lrij[inrij[inrijpos].recordnr].naam << "\t" << lrij[inrij[inrijpos].recordnr].gebjaar << "\t" << lrij[inrij[inrijpos].recordnr].postcode << "\t " << lrij[inrij[inrijpos].recordnr].huisnr << endl ; */ } }
12 3. Recursie a)Struct voor posities: struct Pos { int x; int y; }; Alternatief, gebruik een rij van twee waarden: typedef int Pos [2]; Type voor Route: typedef Pos Route [64]; het aantal moet wel kloppen; er kunnen maximaal 8 8 sprongen uitgevoerd worden.
13 3. Recursie b)Bepalen van legale positie: bool legale_positie (Pos p) {return p.x >= 0 && p.x < aantalRijen && p.y >= 0 && p.y < aantalKolommen; } Bepalen of positie al bezet is: bool positie_bezet (Pos p, Route r, int lengte) {for (int i=0; i<lengte; i++) {if (zelfde_pos(p,r[i])) return true; } return false; } Hulpfunctie: bool zelfde_pos (Pos a, Pos b) { return a.x == b.x && a.y == b.y; } test op ondergrens en bovengrens
14 3. Recursie b)Breid route uit met nieuwe positie: void markeer_route (Pos p, Route r, int lengte) {r[lengte] = p; }
15 3. Recursie c)bool paardensprong (Pos van, Pos naar, Route r, int lengte) {if (zelfde_pos (van,naar)) {druk_route_af (r, lengte); return true; } else {for (int mogelijk=0; mogelijk<8; mogelijk++) { Pos volgende = tel_op(van,richtingen[mogelijk]); if (legale_positie (volgende) && !positie_bezet (volgende,r,lengte)) {markeer_route (volgende,r,lengte); if (paardensprong (volgende,naar,r,lengte+1)) return true; } return false; }
16 3. Recursie c)Hulpfuncties: bool zelfde_pos (Pos a, Pos b) {return a.x == b.x && a.y == b.y; } Pos tel_op (Pos a, Pos b) { Pos c = {a.x+b.x,a.y+b.y}; return c; } void druk_route_af (Route r, int lengte) {for (int i=0; i<lengte; i++) cout << “(“ << r[i].x << “,” << r.[i].y << “)”; }
17 3. Recursie c)Hulpdatastructuren: Pos richting [] = {{-1,2},{-1,-2},{-2,1},{-2,-1}, {1,2},{1,-2},{2,1},{2,-1}};
18 3. Recursie d)Als het bord n n groot is, is het langst mogelijke pad n 2 lang, dus O(n 2 ).