Föreläsning 4 Kö Implementerad med array Implementerad med länkad lista Djup kontra bredd Bredden först mha kö
Kö (ADT) En kö fungerar som en kö. Man fyller på den längst bak och tömmer den längst fram (köar). FIFO - first in first out enqueue(element)-köar element sist dequeue()-tar bort första elementet i kön och returnerar detta Möjliga operationer initQueue / freeQueue isEmpty – returnerar true om kön är tom isFull() – vissa implementationer front() – returnerar första elementet utan att ta bort det (size() – returnerar antal elementet i kön)
Kö implementerad med array Att flytta alla element när vi tar bort första elementet blir ineffektivt Cirkulär array: Dequeue: front++Enqueue: rear++ Om rear = size sätt rear = 0 (samma för front) OBS – rear får ej komma ifatt front – full array! frontrear
Kö implementerad med länkad lista Med en enkellänkad lista kommer vi att behöva ta oss igenom hela listan varje gång vi ska köa ett element. Här kan vi välja en dubbellänkad lista som har pekare både till huvud och svans. Eftersom vi bara ska lägga till längst bak och aldrig ta bort inser man att det räcker med en enkellänkad lista som har en extra pekare till sista elementet
Bredd kontra djup När vi letar efter en lösning rekursivt blir det naturligt att vi borrar ner oss djupt kanske utan att hitta lösningen Med hjälp av en kö kan vi enkelt söka fullständigt efter lösningar på varje djup innan vi går vidare Vi ska diskutera utifrån hissexemplet
Hissen (rekursion) Vi har ett hus med 7 våningar (1-7) Startar på våning 1 och ska till våning 2 Det finns två knappar: upp3 – åker upp tre våningar ner1 – åker ner en våning void aka(int upp, int ner,int max, int mal,int vaning,int antalResor){ antalResor++; if(vaning==mal){ printf("Det tog %d resor.\n",antalResor); }else{ if(vaning+upp<=max) aka(upp,ner,max,mal,vaning+upp,antalResor); if(vaning-ner>=1) aka(upp,ner,max,mal,vaning-ner,antalResor); } void aka(int upp, int ner,int max, int mal,int vaning,int antalResor){ antalResor++; if(vaning==mal){ printf("Det tog %d resor.\n",antalResor); }else{ if(vaning+upp<=max) aka(upp,ner,max,mal,vaning+upp,antalResor); if(vaning-ner>=1) aka(upp,ner,max,mal,vaning-ner,antalResor); }
Djupet först Våra rekursiva anrop hamnar på stacken Vi får en algoritm som söker igenom möjligheterna enligt bilden Här måste vi sätta ett maxdjup för att komma fram Ibland är detta dåligt: när vi hittar en lösning vet vi inte om det finns en ”snabbare” (på lägre djup) Ibland är det svårt att välja max-djup upp ner
Djupet först generellt med maxdjup 4
Bredden först generellt Här får vi en lösning som vi vet är en av de snabbaste lösningarna! Om vi vet att det finns en lösning behöver vi inte sätta någon maxgräns För att åstadkomma detta behöver vi dock en kö!
Bredden först med hissen Våning 1. Köa upp (4). Kö: 4 Avköar våning 4. Vi köar upp (7) och ner (3). Kö: 7, 3 Avköar våning 7. Vi köar ner (6) Kö: 3, 6 Avköar våning 3. Vi köar upp (6) och ner (2) Kö: 6, 6, 2 Avköar våning 6. Vi köar ner (5) Kö: 6, 2, 5 Avköar våning 6. Vi köar ner (5) Kö: 2, 5, 5 Avköar våning 2. upp ner
Köa hissen För att kunna köa de olika positionerna i trädet behöver vi använda en struct som representerar en position: typedef struct { int antalResor; int vaning; } Data; Dessutom behöver vi en kö: typedef struct { Node *front, *rear; } Queue; Med denna och tillhörande metoder helst i en separat fil kan vi sedan relativt enkelt lösa hissen med bredden först:
int main(){ Queue *q = initQueue(); int upp=15, ner=8, max=78, mal=35; Data d; d.antalResor=0; d.vaning=1; while(d.vaning!=mal){ (d.antalResor)++; if(d.vaning+upp<=max){ d.vaning+=upp; enqueue(q,d); d.vaning-=upp; } if(d.vaning-ner>=1){ d.vaning-=ner; enqueue(q,d); } d=dequeue(q); } printf("Det tog %d resor.",d.antalResor); freeQueue(q); return 0; } int main(){ Queue *q = initQueue(); int upp=15, ner=8, max=78, mal=35; Data d; d.antalResor=0; d.vaning=1; while(d.vaning!=mal){ (d.antalResor)++; if(d.vaning+upp<=max){ d.vaning+=upp; enqueue(q,d); d.vaning-=upp; } if(d.vaning-ner>=1){ d.vaning-=ner; enqueue(q,d); } d=dequeue(q); } printf("Det tog %d resor.",d.antalResor); freeQueue(q); return 0; }
Inlämningsuppgifter Följande uppgifter redovisas senast måndag den 4 januari och kan inte redovisas senare: 4A, 4B, 4.4 (utgå från föreläsningen och använd gärna din kö skapad för 4B för att lösa 4.4), 4.1 Dessa uppgifter bör göras nu för att ni ska kunna följa kursen på ett bra sätt. Övriga kan ni göra vid tillfälle för högre betyg.
Uppgifter ej i boken 4.A Implementera en kö som lagrar heltal med hjälp av en cirkulär array. Den ska minst ha operationerna enqueue, dequeue, isEmpty, isFull. Se till att det går att använda flera köer. Använd följande struct för att definiera en kö: typedef struct{ int front, rear; int element[MAXQ]; } Queue; Skriv också en main som testar din kö. (3p) 4.B Implementera en kö med hjälp av en enkellänkad lista med en extra pekare till slutet. Den ska lagra en struct Bok som innehåller titel och utgivningsår. Den ska minst ha operationerna enqueue, dequeue, isEmpty. Använd gärna structen från föreläsningen och separata filer. Skriv också en main som testar din kö. (3p)