Examen Programmeren 2e Bachelor Elektrotechniek en Computerwetenschappen Faculteit Ingenieurswetenschappen Academiejaar 2008-2009 22 Juni, 2009 **BELANGRIJK** 1. Schrijf je naam onderaan op elk blad. 2. Dit deel handelt enkel over C (geen C++!). 3. Kladpapier vind je achteraan. 4. Veel succes! (op 8 punten van de 20) A. PriorityQueue [4/8] Deze vraag handelt over een binary heap, die generische Item elementen bevat. Gebruik hierbij uitsluitend C en geen C++. Let wel: het eerste element van de heap-array staat op index 0 en niet op index 1! Gegeven volgende header bestanden: Item.h #ifndef H_ITEM #define H_ITEM typedef double Item; #define key(a) (A) #define less(a, B) (key(a) < key(b)) #define exch(a, B) { Item t = A; A = B; B = t; } #endif PriorityQueue.h #ifndef H_PQ #define H_PQ #include "Item.h" typedef struct PQ{ Item* heap; int n; /* aantal aanwezige elementen */ int maxn; /* maximaal aantal elementen */ } PQ; Naam:.. blz. 1
PQ* init(int maxn); /* intialiseert een PQ met maximaal maxn elementen*/ int empty(pq* pq); /*return values: 1 indien lege heap; 0 in elk ander geval */ int insert(pq* pq, Item item); /* voegt item toe in de PQ, return values: 0 indien gelukt; -1 in elk ander geval */ void fixup(pq* pq, int k); /* herstelt de heap-eigenschap */ void fixdown(pq* pq, int k); /* herstelt de heap-eigenschap */ int getmax(pq* pq, Item* max); /* geeft het maximum terug via max */ void destroy(pq* pq); /* geeft de PQ vrij */ #endif a. Geef de implementatie van de functie init [op 1 punt van de 20] PQ* init(int maxn) b. Zou men voor de functie destroy ook volgende declaratie kunnen nemen: void destroy(pq pq);? Waarom (niet)? [op 0.5 punten van de 20] Geef ook de implementatie van deze functie. [op 1 punt van de 20]. void destroy(pq* pq) Naam:.. blz. 2
c. Geef de implementatie van de functies insert en fixup. [elk 0.75 punten van de 20] int insert(pq* pq, Item item) void fixup(pq* pq, int k) B. Contact Record [4/8] Gegeven de volgende header file, contact_record.h: enum number_type {MOBILE = 0, PRIVATE = 1, WORK = 2}; struct contact_record { char* contact_name; char*** numbers; int* numbers_size; }; typedef struct contact_record contact; contact init_record(char* contact_name); void add_number(contact* c, enum number_type numbertype, char* number); void delete_number(contact* c, char* number); void delete_contact(contact* c); void print_contact(contact* c); Een contact heeft dus een naam en een array numbers die de mobiele, privé- en werknummers bijhoudt. Naam:.. blz. 3
Een voorbeeld van de interne structuur van de numbers array kan als volgt schematisch worden weergegeven: De numbers_size array houdt bij hoeveel nummers van elke soort aanwezig zijn in numbers. In het voorbeeld zou die dus opeenvolgend 2, 0 en 1 bevatten. In wat volgt mag je steeds veronderstellen dat er genoeg geheugen voorhanden is zodat alle allocaties altijd succesvol zijn, op return waarden van de functies malloc, calloc en realloc hoeft dus niet gecontroleerd te worden. a. Gegeven de volgende implementatie van de functie init_record. Er zitten echter 4 fouten of onvolledigheden in de code. Duid deze duidelijk aan en corrigeer. [op 1 punt van de 20] contact init_record(char* contact_name){ contact c; } int i; c.contact_name = (char*)malloc(strlen(contact_name)); strcpy(c.contact_name,contact_name); c.numbers = (char***)malloc(3*sizeof(char**)); c.numbers_size = (int*)malloc(sizeof(int)); for(i = MOBILE; i < WORK; i++){ c.numbers[i] = 0; c.numbers_size[i] = 0; } return c; Naam:.. blz. 4
b. Gegeven de volgende implementatie van de functie add_number. Vul de ontbrekende code voor de nodige allocaties aan. [op 1.5 punten van de 20] void add_number(contact* c, enum number_type numbertype, char* number){ c->numbers_size[numbertype]++; //VUL AAN! } strcpy(c->numbers[numbertype][c->numbers_size[numbertype]-1], number); c. Men wil nu in de PriorityQueue uit deel A contact records opslaan. Hiertoe dient enkel de Item.h header file aangepast te worden. Geef deze aanpassingen, wetende dat contact records op contact_name gesorteerd worden. [op 1.5 punten van de 20] #ifndef H_ITEM #define H_ITEM typedef double Item; #define key(a) (A) #define less(a, B) (key(a) < key(b)) #define exch(a, B) { Item t = A; A = B; B = t; } #endif Naam:.. blz. 5
KLADPAPIER: Naam:.. blz. 6
Examen Programmeren 2e Bachelor Elektrotechniek en Computerwetenschappen Faculteit Ingenieurswetenschappen Academiejaar 2008-2009 22 Juni, 2009 **BELANGRIJK** 1. Lees eerst de volledige opgave (inclusief de hints/opmerkingen)! 2. Schrijf je naam, stamnummer en richting bovenaan elk cpp bestand. 3. Bestudeer aandachtig de gegeven header bestanden; ze bevatten extra informatie over de te implementeren functies en de werking van de code. 4. Kladpapier vind je achteraan 5. Veel succes! (op 12 punten van de 20) A. Balancering van een binaire zoekboom [9/12] Een binaire zoekboom slaat elementen op aan de hand van een sleutelwaarde. Hier zijn de sleutels gelijk aan de elementen zelf. De prestaties van zoekoperaties op binaire zoekbomen (handboek hoofdstuk 12) kunnen echter nefast beïnvloed worden wanneer de boom ongebalanceerd is. Daarom kan men trachten om de boom gebalanceerd te houden door af en toe een balanceringsoperatie uit te voeren. Een exhaustief algoritme voor balancering kan als volgt beschreven worden: - Zoek de mediaan van alle sleutelwaarden in de boom o Overloop de boom volledig o Voeg de bezochte elementen gesorteerd toe in een STL vector o Het middelste element in de vector is de mediaan - Roteer de mediaan door middel van linkse en rechtse rotaties naar de wortel van de boom - Doe recursief hetzelfde voor de resulterende linker- en rechterdeelbomen van de nieuwe wortel Dit exhaustief algoritme garandeert een volledig gebalanceerde boom na afloop. Gegeven de header en cpp-bestanden BinarySearchTree.h, BinarySearchTree.cpp, template_instantiations.cpp en main.cpp. Volgende methoden zijn reeds aanwezig: - showtree, show en printnode: zorgen samen voor het afprinten van een 90º gedraaide versie van de boom Naam:.. blz. 7
- insert: voegt een element toe op de juiste plaats in de boom afhankelijk van zijn sleutelwaarde. Hierbij wordt GEEN root insertion (handboek hoofdstuk 12.8) toegepast. - findmedian: geeft de mediaan terug van alle sleutelwaarden in de boom; roept hiertoe de findmedianelement methode op. - balance: balanceert de boom volgens het hierboven uitgelegde algoritme; roept hiertoe de balancesubtree methode op. - rotl en rotr: voeren een rotatie uit tussen een node en zijn rechterrespectievelijk linkerkind, wat resulteert in het naar links respectievelijk rechts roteren van de node. Deze methoden worden opgeroepen in de balancesubtree methode. - destructor: geeft het geheugen ingenomen door de boom vrij; roept hiertoe de freetree methode op. Gevraagd: vul BinarySearchTree.cpp verder aan. Meerbepaald, implementeer: constructor (1 punt) : initialiseert de boom freetree (2 punten): geeft de (deel)boom vrij waarvan de wortel is meegegeven als argument. Deze methode kan je zowel recursief als iteratief implementeren: maak een keuze, één implementatie volstaat uiteraard! traverseandsort (2 punten): voegt de elementen in de (deel)boom, waarvan de wortel is meegegeven als argument, gesorteerd toe aan de opgegeven vector. Deze methode kan je best recursief implementeren. findmedianelement (2 punten): gebruikt het hierboven uitgelegde algoritme voor het bepalen van de mediaan van de (deel)boom waarvan de wortel is meegegeven als argument, en geeft de pointer terug naar het TreeElement dat die mediaan bevat. Maak hierbij gebruik van traverseandsort. balancesubtree (2 punten): gebruikt het hierboven uitgelegde exhaustieve algoritme om de (deel)boom met opgegeven wortel te balanceren. Maak hierbij gebruik van findmedianelement en de rotatiemethoden. Deze methode kan je het best recursief implementeren. Enkele hints/opmerkingen: Je mag de BinarySearchTree.h header NIET aanpassen! Doe je dit toch, dan verlies je punten. Voor jullie gemak worden achteraan de opgave de rotl en rotr functies schematisch voorgesteld. Deze functies zal je correct moeten gebruiken in de balancesubtree functie. Hoofdstuk 5.6 van het handboek en volgende handelen over tree traversal... In de main methode kan je gemakkelijk enkel je BinarySearchTree testen door de functie testbst uit te voeren. Deze zal een BinarySearchTree van int s aanmaken, en er de gevraagde methoden op testen. Naam:.. blz. 8
B. SensorData klasse [3/12] Men wil de binaire zoekboom nu gebruiken om de data verkregen uit omgevingssensoren op te slaan. Dergelijke SensorData-objecten houden een sensor id bij en 5 rijen uitgelezen waarden van de sensor (HUMIDITY en TEMPERATURE) met hun corresponderende timestamp (i.e. wanneer de waarden zijn geregistreerd door de sensor). Het aantal rijen en kolommen in de tabel data is steeds gelijk aan de constanten NR_ROWS en NR_COLS gedefinieerd in de header file. Gegeven het header bestand SensorData.h en de cpp bestanden SensorData.cpp en main.cpp. Gevraagd: vul SensorData.cpp en SensorData.h verder aan. Declaratie en implementatie van: (beiden op 1.5 punt) de vergelijkingsoperator < die objecten vergelijkt volgens de gemiddelde waarde van TEMPERATURE over de 5 meetmomenten de outputoperator << die objecten uitschrijft in de volgende vorm: Sensor <id> has data: <timestamp> <humidity> <temperature> Bijvoorbeeld: Sensor 1 has data: 15.26 90.5 23.6 15.36 90.4 23.2 15.46 90.5 23 15.56 90 23 16.06 90 23 Voor het testen van je SensorData kan je gebruik maken van de testsd methode. Veel succes! Naam:.. blz. 9
De gestippelde pijlen geven de pointers aan die door de rotatie veranderd zijn. Naam:.. blz. 10
KLADPAPIER: Naam:.. blz. 11