Kap 6: Lista, stack och kö



Relevanta dokument
Introduktion till algoritmer - Lektion 3 Matematikgymnasiet, Läsåret Lektion 3

Skizz till en enkel databas

Att använda pekare i. C-kod

TDIU01 - Programmering i C++, grundkurs

TDIU01 - Programmering i C++, grundkurs

Lösningar till tentauppgifterna sätts ut på kurssidan på nätet idag kl 19. Omtentamen i Programmering C, 5p, fristående, kväll,

4 Sammansatta datatyper

C++ Lektion Tecken och teckenfält

Övningar Dag 2 En första klass

Programmering, grundkurs, 8.0 hp, Elektro, KTH, hösten 2010

TDIU01 (725G67) - Programmering i C++, grundkurs

E-post för nybörjare

TDDC76 - Programmering och Datastrukturer

C++ Slumptalsfunktioner + switch-satsen

Programmeringsteknik med C och Matlab

C++ Funktioner 1. int summa( int a, int b) //funktionshuvud { return a+b; //funktionskropp } Värmdö Gymnasium Programmering B ++ Datainstitutionen

Föreläsning 3.1: Datastrukturer, en översikt

Kap 4: Mer om char och stränghantering

TDIU01 - Programmering i C++, grundkurs

2. Komma igång Skapa grupper och elever Skriv också ut sidan 13 så att eleverna har en snabbguide till programmet.

Tentamen i Objektorienterad programmering

Tentamen DE12, IMIT12, SYST12, ITEK11 (även öppen för övriga)

Objektorienterad programmering i Java

LÖSNINGSFÖRSLAG TILL Tentamen i objektorienterad programmering i C++ I

PROGRAMMERING 2 GRUNDLÄGGANDE SEMANTIK 4

PROGRAMMERING A VC# 2008 EXPRESS UTVECKLINGSVERKTYGET VISUAL C#

Tentamen OOP

Innehåll. Introduktion till objektorientering. OOP (objektorienterad programmering) Objekt, instanser, klasser

TDDC76 - Programmering och Datastrukturer

19. Skriva ut statistik

Programmering A C# VT Ett kompendie över Programmering A (50p) i c# Stefan Fredriksson

Dagens föreläsning. Repetition. Repetition - Programmering i C. Repetition - Vad C består av. Repetition Ett första C-program

Objektorienterad programmering D2

Introduktion till arv

1 Texthantering. 1.1 Typen char. Exempel, skriv ut alfabetet

Lösningar till uppgifterna sätts ut på kurssidan på nätet idag kl Omtentamen i Programmering C, 5p, A1, D1, E1, Fri, Pr1, Te/Ek1,

OOP Objekt-orienterad programmering

Tentamen på kursen DA7351, Programmering , kl Malmö högskola Teknik och samhälle. DA7351, Programmering

TDIU01 - Programmering i C++, grundkurs

6 Rekursion. 6.1 Rekursionens fyra principer. 6.2 Några vanliga användningsområden för rekursion. Problem löses genom:

TDIU01 - Programmering i C++, grundkurs

Grundläggande programmering med C# 7,5 högskolepoäng

1 Funktioner och procedurell abstraktion

Sätt att skriva ut binärträd

TDP004. Minne och pekare. Eric Elfving Institutionen för datavetenskap

C++ - En introduktion

Textsträngar från/till skärm eller fil

SMD 134 Objektorienterad programmering

Algoritmanalys. Genomsnittligen behövs n/2 jämförelser vilket är proportionellt mot n, vi säger att vi har en O(n) algoritm.

TDIU01 - Programmering i C++, grundkurs

TAIU07 Matematiska beräkningar med Matlab

Tecken. char. char ch = A ; sizeof(char) = 1 byte (ej 16-bitars tecken som i Java) char namn[]= "Nils"; // längd = 5 bytes

Chapter 3: Using Classes and Objects

Innehållsförteckning. Exempel. Åtkomst & användarhandledning

LÄSLANDET - BOKSTÄVER OCH ORD

Övningar i JavaScript del 2

E-POST3 Ett lättanvänt e-postprogram med stöd för talsyntes

5 Grundläggande in- och utmatning

Björn Abelli Programmeringens grunder med exempel i C#

Tentamen för kursen Objektorienterad programvaruutveckling GU (DIT010)

Föreläsning 6: Introduktion av listor

Tentamen i. för D1 m fl, även distanskursen. fredag 13 januari 2012

Lösningar till uppgifterna sätts ut på kurssidan på nätet i dag kl Tentamen i Programmering C, Fri, Kväll,

RödGrön-spelet Av: Jonas Hall. Högstadiet. Tid: minuter beroende på variant Material: TI-82/83/84 samt tärningar

Kapitel 15: Data/Matrix Editor

TDIU01 - Datortenta (DAT2)

Läs detta innan du fortsätter, eller skriv ut det, klicka runt lite och läs samtidigt.

Programmering i C++ En manual för kursen Datavetenskaplig introduktionskurs 5p

Tentaupplägg denna gång

Datorsystem Laboration 2: Minnesmappade bussar

Får jag be om ordet!

TDDC76 - Programmering och Datastrukturer

Föreläsningsanteckningar 3. Mikroprogrammering II

Föreläsning 13 och 14: Binära träd

Enkla datatyper minne

Digital Display VDS / Bus2

Datorövningar. Grunderna i C/C++

B = Bokad tid. T = Tillfälligt bokad tid. L = Ledig tid. X = Spärrad tid

Programmering i C++ EDA623 Strömmar och filer. EDA623 (Föreläsning 9) HT / 19

Kompilering och exekvering. Föreläsning 1 Objektorienterad programmering DD1332. En kompilerbar och körbar java-kod. Kompilering och exekvering

Användarhandledning Version 1.2

Referens till. WeavePoint 6 Mini

Redovisning av inlämningsuppgifter

Rolladministration i PaletteArena 5.3

16 Programmering TI -86 F1 F2 F3 F4 F5 M1 M2 M3 M4 M5

Projektarbete 2: Interaktiv prototyp

ÖREBRO UNIVERSITET. Lösningarna till tentamensuppgifterna sätts ut på kurssidan på nätet i dag kl 13.

Användarmanual flexconnect.se Administratör

Vem är vem på kursen. Objektorienterad programvaruutveckling GU (DIT011) Kursbok Cay Horstmann: Big Java 3rd edition.

Programmering Grundkurs (6H2950) Grundläggande Programmering (6A2001)

FÖRSLAG TILL LÖSNING AV Tentamen i Objektorienterad programmering C++ I

Färgklövern. Färgklövern är gjord 1998 i samarbete mellan Datateket i Linköping och Hargdata AB i Linköping.

Konfigurera Xenta från Point

Föreläsning 1 & 2 INTRODUKTION

Uppgift (poäng) 1 (2) 2 (3) 3 (4) 4 (4) 5 (3) 6 (4) 7 (6) 8 (6) 9 (8) Summa

Med CW DoorDesign registreras all beslagning på dörren. För att hantera låsning och låsning mot dörr se manualen för CW KeyDesign.

En kort text om programmering i C.

Administration - Skapa och administrera användare. Din roll som administratör 1. Meny och huvudfunktioner 2-4. Skapa en användare...

Elektroteknik MF1016 föreläsning 9 MF1017 föreläsning 7 Mikrodatorteknik

Flexibel meny i Studentportalen

Transkript:

Kap 6: Lista, stack och kö Vi har använt vector en hel del i boken. Det finns andra liknande konstruktioner, som också har tillkommit under senare år. I det här kapitlet ska vi lära oss använda: list, stack och queue, dvs lista, stack och kö. Vi går igenom dessa i tur och ordning och bygger exempelprogram, som visar hur de används. Vi ska också diskutera skillnader och likheter och ge exempel på användning. 1. Funktioner i list och jämförelse med vector Vi börjar med att skapa ett instruktivt program, som visar hur list används och vilka funktioner som finns. Skapa en ny mapp Kap 06 med projektet Ex01_06 och cpp-filen Ex01. Lägg in koden: // Ex01_06. Genomgång av funktioner till list #include <iostream> #include <list> #include <conio+.h> // Räcker med conio.h i Builder using namespace std; #include svtecken.h void pos_text(int& x, int& y, string s, int nya_rader=2); void skriv(list<double> lista); int main() teckenbyt(); list<double> lista; int x, y, i; lista.push_back(3.6); lista.push_back(4.5); lista.push_back(2.9); pos_text(x, y, Tryck tangent för att skriva ut listan:, 1); gotoxy(x,y); clreol(); cout << Listan från början: ; skriv(lista); pos_text(x, y, Tryck för att lägga till 1.1 i listans början: ); lista.push_front(1.1); gotoxy(x,y); clreol(); cout << Listan med 1.1 tillagt i början: ; skriv(lista); pos_text(x, y, Tryck för att lägga till 2.2 i listans slut: ); lista.push_back(2.2); gotoxy(x,y); clreol(); cout << Listan med 2.2 tillagt i slutet: ; skriv(lista); pos_text(x, y, Tryck för att lägga in 3.3 på 4:e plats: ); list<double>::iterator it = lista.begin(); for (i=1; i<4; i++) it++; lista.insert(it, 3.3); gotoxy(x,y); clreol(); cout << Listan med 2.2 på 4:e plats: ; skriv(lista); cout << \n\n\n ; cout << Tryck tangent ; getch(); return 0;

void pos_text(int& x, int& y, string s, int nya_rader) cout << \n ; if (nya_rader>1) cout << \n ; x=wherex(); y=wherey(); cout << s; getch(); void skriv(list<double> lista) list<double>::iterator it = lista.begin(); for (unsigned int j=0; j<lista.size(); j++) cout << *it++ << ; Kör programmet. Som du ser finns det många funktioner som är lika i list och vector. Man lägger till element med push_back() men kan också lägga till element ned push_front() i list. En lista kan inte indexeras och kräver en speciell konstruktion, iterator, för att adressera en lista: list<double>::iterator it = lista.begin(); Ovan deklareras en iterator it, som sätts att peka på listans första element. Iteratorn kan också enkelt sättas till ett steg efter sista elementet med lista.end, men för övrigt måste man iterera, exempelvis med en for-loop, för att ge iteratorn it rätt värde. Följande sats skriver listans värde: for (unsigned int j=0; j<lista.size(); j++) cout << *it++ << ; Som du ser används it++ för att öka iteratorn it med 1. Det värde som iteratorn pekar på anges med *it. Man sätter alltså tecknet * framför iteratorn för att komma åt själva värdet. Koden cout << it++ skriver ut värdet av elementet it och ökar sedan iteratorn med 1. Även vector kan använda iteratorer men det finns inte samma behov där som i list. Mycket verkar annars vara lika i vector och list. Som konstruktioner är de dock mycket olika. I en vector lagras elementen i minnet efter varandra, men en listas element kan ligga på helt olika minnesplatser. Fördelen med list jämfört med vector är, att det tar kortare tid att ta bort eller lägga till ett element vilket som helst. I vector går det endast snabbt att radera eller lägga till element i slutet av vektorn. Hur är elementen uppbyggda i list? Jo, de består av två delar: en datadel och en adressdel. Första elementet innehåller adressen till det andra elementet, som i sin tur innehåller adressen till nästa o s v. Bilden nedan visar en lista bestående av fem element. Den vänstra delen av varje element symboliserar där datadelen och den högra adressdelen: 1 2 3 4 5 Element i en lista kan tas bort genom att enbart flytta adresser. Exempelvis tas element tre bort om dess adress, som pekar på element fyra, istället flyttas till element två. Det som tidigare var fjärde elementet blir nu tredje. Adresserna till listans kvarstående element är dock samma som förut. 1 2 3 4

Så är det inte i vector. Raderas ett element kommer alla element till höger om det raderade att ändra adress. Motsvarande gäller om element läggs till i en vektor utom på slutet. Läggs element till i slutet kan tidigare element behålla sina adresser. Vi ska fortsätta med fler funktioner i vårt program. Lägg in resten av koden nu: pos_text(x, y, Tryck för att sortera listan: ); lista.sort(); gotoxy(x,y); clreol(); cout << Listan sorterad: ; skriv(lista); pos_text(x, y, Tryck för att vända på listan: ); lista.reverse(); gotoxy(x,y); clreol(); cout << Listan vänd: ; skriv(lista); pos_text(x, y, Tryck för att ta bort 3:e talet: ); it = lista.begin(); for (i=1; i<3; i++) it++; lista.erase(it); gotoxy(x,y); clreol(); cout << Listan med talet nr 3 raderat: ; skriv(lista); pos_text(x, y, Tryck för att ta bort 3:e och 4:e talet: ); it = lista.begin(); for (i=1; i<3; i++) it++; list<double>::iterator it2 = lista.begin(); for (i=1; i<5; i++) it2++; lista.erase(it,it2); gotoxy(x,y); clreol(); cout << Listan med tal nr 3 och 4 raderat: ; skriv(lista); pos_text(x, y, Tryck för att kopiera listan: ); list<double> lista2=lista; gotoxy(x,y); clreol(); cout << Listan kopierad: ; skriv(lista); cout << Kopia: ; skriv(lista2); pos_text(x, y, Tryck för att radera listans 1:a tal och jämföra: ); lista.erase(lista.begin()); gotoxy(x,y); clreol(); if (lista!=lista2) cout << Listorna är olika! ; skriv(lista); cout << Kopian: ; skriv(lista2); pos_text(x, y, Tryck för att radera listan: ); lista.clear(); gotoxy(x,y); clreol(); cout << Listan: ; skriv(lista); if (lista.empty()) cout << Listan är tom! ; Kör programmet igen. Som du ser finns en funktion sort(), som sorterar en lista i stigande ordning, och genom att vända på listan med reverse() kan listan också sorteras fallande. Om listan innehåller string-strängar fungerar dock inte sortering av svenska tecken. Man raderar element med erase() men måste då använda en iterator liksom när insert() används. Om flera element ska raderas måste två iteratorer användas. En fördel med vector är att iteratorer inte behövs direkt men kan användas. Många av skillnaderna märker man inte mycket av som användare. Det är enkelt att kopiera en lista

liksom en vektor och det är också lätt att radera hela listan eller vektorn. Funktionen empty() finns både i list och vector. Man kan sätta samman listor med merge(), infoga en lista i en annan på valfri plats med splice() och ta bort lika element med unique(). Men det leder för långt att gå in på allt detta. I tabellen nedan, som visar funktioner i list och vector, finns inte dessa sista funktioner med. Funktionens namn Gör följande Finns i assign(antal, varde) Ger platserna 0 till antal-1 värdet varde vector size() Returnerar längden vector, list begin() Ger platsen för första elementet vector, list end() Ger platsen för sista elementet+1 vector, list push_back(element) Lägger till element i slutet vector, list push_front(element) Lägger till element i början lista insert(it, element) Lägger in element på plats som anges av it vector, list erase(it) Raderar elementet som plats som anges av it vector, list sort() Sorterar elementen i stigande ordning list reverse() Vänder på ordningsföljden list clear() Raderar alla element vector, list empty() Returnerar true om inga element finns vector, list = Tilldelar en vektor eller lista till en annan vector, list ==!= <= > >= Används för jämförelse vector, list Uppgift 1, Uppgift 2 2. En lista med struct Vi ska skriva ett program med en lista av struct för att visa hur list fungerar med strukturer. Skapa ett nytt projekt Ex02_06 med cpp-filen Ex02. Programmet ska vara meny- och funktionsuppbyggt. Koden nedan implementerar funktionerna mata_in() och skriv_ut(), men fler funktioner kommer att läggas in. Lägg in följande kod i cpp-filen: // Ex02_06. Program som visar en lista med struct #include <iostream> // För Visual #include <fstream> #include <list> #include <conio+.h> // Räcker med conio.h i Builder using namespace std; #include svtecken.h #include egna_funktioner.h struct Konto string namn;

string nr; double kapital; ; void meny(char& ch); void mata_in(list<konto>& kontolista); void skriv_ut(list<konto> kontolista); int main() teckenbyt(); list<konto> kontolista; char ch; meny(ch); while (ch!='0') switch (ch) case '1': mata_in(kontolista); break; case '2': skriv_ut(kontolista); break; case '3': break; case '4': break; case '5': break; case '6': break; case '7': break; case '8': break; case '9': break; meny(ch); cout << \n\n ; return 0; void meny(char& ch) clrscr(); cout << \n Meny ; cout << \n\n 1. Mata in konto\n 2. Skriv ut alla konton << \n 3. Radera konto\n 4. Infoga konto\n 5. Radera alla konton << \n 6. Sortera konton\n 7. Söka efter konto\n << 8. Spara konton som fil\n 9. Hämta konton från fil\n << 0. Avsluta ; cout << \n\n Välj genom att trycka siffertangent: ; ch=getch( 0123456789 ); void mata_in(list<konto>& kontolista) Konto konto; clrscr(); cout << \n Inmatning av konton:\n ; cout << \n Mata in namn (sluta - mata in tomsträng): ;

while (getline(cin, konto.namn) && konto.namn!= ) cout << Mata in kontonummer: ; getline(cin, konto.nr); cout << Mata in kapital: ; cin >> konto.kapital; cin.ignore(1000,'\n'); kontolista.push_back(konto); cout << \n Mata in namn (sluta - mata in tomsträng): ; void skriv_ut(list<konto> kontolista) clrscr(); cout << \n Kontolistan:\n\n ; list<konto>::iterator it; Konto konto; for (it=kontolista.begin(); it!=kontolista.end(); it++) konto=*it; cout << << konto.namn << << konto.nr << << konto.kapital << endl; cout << \n Tryck tangent ; getch(); Kör programmet. Som du ser av strukturen Konto ska programmet använda bankkonton med datamedlemmarna namn, nr och kapital. De första två är string-variabler och kapital en double. Menyn kommer att innehålla nio alternativ när programmet är färdigt. Som framgår av switch-satsen har endast de två första implementerats i koden hittills. I funktionen meny() skrivs menyn ut och tecken för att välja i menyn matas in av användaren. Parametern ch är referensparameter och överför tecknet till main(), där det tas om hand av switch-satsen. I meny() används den överlagrade getch() från Övning 5 i föregående kapitel. Har du inte lagt in den i egna_funktioner.h bör du göra det nu eller byta till vanlig getch(). I mata_in() sker inmatning tills konto.namn matas in som tomtecken. Det sköts om av whilevillkoret (getline(cin, konto.namn) && konto.namn!= ) som är true så länge som konto.namn inte är en tomsträng. Vi har inte använt oss av just den här konstruktionen tidigare. Det innebär att read ahead-teknik, som ofta använts tidigare, inte behövs. I skriv_ut() används iterator för att skriva ut kontolistan. Den konstruktionen känner du igen från föregående avsnitt. Vi ska implementera fil_skriv() och fil_hamta(), vilket delvis blir repetition från kapitel 3: Prototyper: void fil_skriv(list<konto>& kontolista); void fil_hamta(list<konto>& kontolista); Funktionsdefinitioner: void fil_skriv(list<konto>& kontolista) clrscr(); cout << \n Skrivning till fil\n ; list<konto>::iterator it = kontolista.begin(); Konto konto;

string filnamn; cout << \n Mata in filnamn: ; getline(cin,filnamn); if (filnamn!= ) if (filnamn.find('.')==-1) filnamn=filnamn+.txt ; ofstream fout(filnamn.c_str()); if (!fout) cout << \n Filen går ej att öppna. Tryck tangent ; getch(); exit(1); for (it; it!=kontolista.end(); it++) konto=*it; fout << konto.namn << endl << konto.nr << endl << konto.kapital << endl; cout << \n Skriver filen... ; delay(2000); fout.close(); void fil_hamta(list<konto>& kontolista) clrscr(); cout << \n Hämtning från fil\n ; string filnamn; cout << \n Mata in filnamn: ; getline(cin,filnamn); if (filnamn!= ) if (filnamn.find('.')==-1) filnamn=filnamn+.txt ; ifstream fin(filnamn.c_str()); if (fin) cout << \n Läser filen... ; delay(2000); kontolista.clear(); Konto konto; while (getline(fin, konto.namn) &&!fin.eof()) getline(fin, konto.nr); fin >> konto.kapital; kontolista.push_back(konto); fin.ignore(1000,'\n'); fin.close(); else cout << Hittar inte filen. Tryck tangent ; getch(); skriv_ut(kontolista); I switch-satsen i main() byts raderna med case-fall '8' och '9' mot: case '8': fil_skriv(kontolista); meny(ch); break; case '9': fil_hamta(kontolista); meny(ch);

Kör programmet. I fil_skriv() måste iterator användas vid skrivning till filen med fout. Se koden nedan. Observera att struct-medlemmarna inte kan kommas åt med *it.namn, *it.nr och *it.kapital utan en struct-variabel av typ Konto måste tilldelas det värde som iteratorn pekar på. Sedan kan skrivning till textfilen ske. for (it; it!=kontolista.end(); it++) konto=*it; fout << konto.namn << endl << konto.nr << endl << konto.kapital << endl; I fil_hamta() har, liksom i mata_in(), använts ett while-villkor som gör read ahead-teknik överflödig. while (getline(fin, konto.namn) &&!fin.eof()) Inläsning från filen sker så länge som getline() läser en sträng till konto.namn och läsningen inte resulterar i att eof() returnerar false. Funktionen delay() i egna_funktioner.h har använts för att ge en illusion av arbete under 2 sekunder. Spara allt. Uppgift 3, Uppgift 4 3. Sortering av struct-listan Skapa ett nytt projekt, Ex03_06, med samma innehåll i cpp-filen Ex03 som i föregående projekt, som nu ska utökas. Vi ska ordna så att kontolistan kan sorteras i programmet. Det är ju bara att använda sort(), tänker man först. Men det fungerar inte i en struct-lista. Hur ska man kunna ange, vad som ska sorteras. Det finns ju tre medlemmar i strukturen Konto. Vilken ska bestämma sorteringsordningen. Vi får skrinlägga planer på användning av sort() och istället skriva en egen funktion. Naturligtvis kan en av sorteringsalgoritmerna från kapitel 4 användas. Det kan göras om minst två iteratorer används. I praktiken visar det sig dock vara krångligt och resulterar i relativt lång kod. Det beror på att iteratorerna måste stegas upp igen efter varje erase() och insert(). Att byta konto på ett ställe i listan innebär att ett element raderas och det nya läggs in på dess plats. Först måste alltså erase()och sedan insert() användas med fungerande iteratorer. Vi ska använda en annan teknik, som är en variant av sorteringsalgoritmerna. Först kommer vi att skaffa oss en kopia av kontolistan och radera allt i originalet. Därefter ska listan genomsökas för att bestämma det konto, som har ett namn först i bokstavsordning. Det kontot ska placeras i det tomma originalet och kontot ska raderas i kopian. Sedan bestäms på nytt vilket konto, som innehåller ett namn först i bokstavsordning. Även det läggs in i kontolistan efter det föregående och raderas från kopian. Om det här får pågå tills kopian är tom måste kontolistan innehålla alla konton sorterade i stigande ordning. Lägg in ändringen i switch-satsen: case '6': sortera(kontolista); meny(ch); break;

Lägg in prototypen: void sortera(list<konto>& kontolista); Lägg också in koden till funktionen: void sortera(list<konto>& kontolista) clrscr(); cout << \n\n Sorterar listan... ; delay(2000); list<konto> lista=kontolista; kontolista.clear(); list<konto>::iterator it; Konto konto; string min; while (!lista.empty()) it=lista.begin(); konto=*it; min=konto.namn; for (++it; it!=lista.end(); it++) konto=*it; if (konto.namn<min) min=konto.namn; for (it=lista.begin(); it!=lista.end(); it++) konto=*it; if (konto.namn==min) kontolista.push_back(konto); lista.erase(it); break; skriv_ut(kontolista); Kör programmet och pröva att sortera kontolistan. Här är funktionens längd acceptabel och programmet också relativt enkelt. Först kopieras kontolistan till en lokalt deklarerad lista, kontolistan töms och nödvändiga deklarationer görs. Därefter följer en while-loop. Två for-loopar har placerats inuti while-kroppen. I den första loopen jämförs kontonas namn i tur och ordning med första kontots namn. Slingan börjar alltså med andra kontot: for (++it; it!=lista.end(); it++) Om ++ placeras före it läggs ju först 1 till värdet på it, vilket gör att slingan startar med konto nummer 2. Då ett namn hittas, som är före min i bokstavsordning, läggs det in i variabeln min. Efter loopen innehåller min därför det namn, som är först i bokstavsordning. I den andra forloopen genomsöks listan och när det konto.namn hittas, vars värde tidigare placerades i min, läggs kontot in i den från början tomma kontolistan. Därefter raderas kontot från den kopierade listan innan while-kroppen genomlöps på nytt. Efter det finns nästa konto också i kontolista och är raderad från lista. Då funktionen empty() returnerar true bryts while-loopen. Då är sorteringen klar. Spara allt. Uppgift 5, Uppgift 6

4. Typerna stack och queue Vi har använt vector och list en hel del så här långt. Det är ganska komplicerade konstruktioner med många möjliga funktioner, även om vissa används sällan. Ibland finns behov av enklare strukturer. Därför har stack och queue skapats. Översättning av ordet stack till svenska blir naturligtvis stack och queue betyder kö på engelska. De här datastrukturerna beter sig, som man kan förvänta sig. När heltal läggs på en stack är det som att lägga något på hög: hö på en höstack, tallrikar på en tallriksstapel. Tar man en tallrik tar man den översta och när den har tagits från stapeln är nästa tallrik den översta. Allra sist tar man den understa tallriken och ska en tallrik läggas på högen av tallrikar läggs den överst, vilket medför att högen (stacken) växer igen. Det innebär att den tallrik som först lades på högen (stacken) kommer att tas bort sist av alla. För en stack gäller principen: först in sist ut. Också en kö, queue, fungerar som köer i praktiska livet. I en biografkö står personer, som expedieras en efter en i biljettluckan. Nya personer, som ställer sig i kö, för att köpa biljett måste ställa sig längst bak och på så sätt växer kön. Den som först ställde sig i kön kan också lämna kön först. För en kö gäller principen först in först ut. Både stackar och köer är vanliga i datavärlden. Då funktioner anropas placeras funktionskod på stacken i minnet. Det innebär att minnesadresserna där ökar ju mer kod funktionen innehåller. Det finns pekare, som vi kan kalla startpekare och exekveringspekare. Startpekaren visar var funktionen börjar och exekveringspekaren håller reda på vilken rad som står i tur att exekveras. När funktionen har exekverat färdig, flyttas exekveringspekaren ner till startpekaren igen. Koden på stacken används inte mer och det som lagrats där är inte åtkomligt från den anropande funktionen. Nästa gång funktionen anropas läggs koden på stacken igen. Finns parametervariabler i funktionsanropet placeras de också på stacken. Om vi tänker oss att funktionen anropas från main() kan inte main() känna till variabelvärden som lagrats på stacken. Har exempelvis en int-parameter fått ett värde på stacken känner inte main() till vilket värde det är. Men om funktionen är av returnerande typ överförs naturligtvis variabelns värde till main(). Genom att använda referensparametrar kan flera värden återföras. Då är det inte variablerna, som läggs på stacken, utan istället referenser till dem. En referens är som en instruktion, som talar om var variabeln finns. Referenserna kastas när funktionen returnerar, men på grund av referenserna har koden på stacken ändrat variabler i main() och de ändringarna är naturligtvis kvar i main(). Köer i datavärlden är också vanliga. När du använder datorn ger du kommandon med mus, tangentbord etc. Alla dessa kommandon utgör händelser som läggs på kö av operativsystemet för att sedan utföras i tur och ordning. Du kan exempelvis klicka i texten i ditt ordbehandlingsprogram, trycka en tangent, klicka i fönsterlisten och klicka på en knapp i verktygsfältet. Dessa händelser läggs in i en kö och utförs sedan i tur och ordning. Deklarationer av stack och queue liknar deklarationer av vector och list och allra först måste naturligtvis inkluderingar av stack och queue göras i programmet. Deklarationen stack<int> talserie deklarerar en stack med heltal, där heltal kan placeras på hög. Deklarationen queue<string> strlista deklarerar en kö av strängar av typ string. Liksom med vector och list växer stacken eller kön efter hand och man behöver inte veta eller ange hur många tal, strängar etc, som ska rymmas. Datastrukturen anpassar sig automatiskt efter antalet. Skapa ett nytt projekt så att vi kan bygga ett program, som använder stack och queue. Ge projektet namnet Ex04_06 och spara cpp-filen som Ex06. Lägg in koden på nästa sida i ccp-filen:

// Ex04_06. Program som visar skillnad på stack och kö #include <iostream> #include <stack> #include <conio+.h> // Behövs ju ej i Builder men använd ändå! using namespace std; #include svtecken.h int main() teckenbyt(); stack<int> talserie; int i; cout << \nstack\n\n ; for (i=0; i<10; i++) talserie.push(i); while (!talserie.empty()) cout << talserie.top() << ; talserie.pop(); cout << \n\ntalen \ poppas\ i omvänd ordning.\n\n\n ; cout << \n\n\n ; cout << Tryck tangent ; getch(); return 0; Headerfilen stack inkluderas och en stack stack<int> deklareras och ges namnet talserie. Först skrivs talen 0 9 till stacken med push(), där heltalet som ska läggas på stacken skrivs i parentesen. Sedan följer en while-loop som pågår tills funktionen empty() resulterar true. Det har vi använt med vector och list förut, så det känns igen. I while-kroppen skrivs stackens översta värde ut med hjälp av funktionen top(), som returnerar det översta värdet, som pushades dit senast. Det är endast detta värde, som kan läsas i en stack. En stack är alltså betydligt enklare att handha än vector och list. För att kunna skriva ut även de andra värdena i stacken måste stackens översta element först poppas med pop(). Det är som att poppa popcorn. Popcornen vill gärna flyga iväg. När element poppas i en stack är de därmed borta från stacken. Men då kan nästa värde läsas med top(). Detta sker tills stacken inte har några fler element. Kör programmet. Vi ska bygga ut programmet, som vi ofta gör, genom att lägga in kod också för en kö. Vi måste då först inkludera queue. Det gör vi efter stack: #include <queue> I Builder behövs inte conio+.h inkluderas men vi gör det här ändå, då vi vill påvisa en bugg där, nödvändig att känna till. Kompilera programmet genom att exempelvis försöka köra det. Kompilatorn rapporterar fel i winbase.h, som är en header-fil som inkluderas av windows.h, som i sin tur inkluderas i conio+.h. Det verkar alltså som om inte både queue och conio+.h kan inkluderas i Builder samtidigt. Om vi inte kan åtgärda detta, är det allvarligt eftersom KgData färghantering förutsätter inkludering av conio+.h. Varför det då så här? Det vet vi inte när den här boken skrivs. Men av en slump upptäckte vi hur det kan åtgärdas: inkludera fstream också (eller i istället för iostream).

Lägg in header-filen fstream så ska vi pröva igen: #include <fstream> Pröva att kompilera igen. Det går utmärkt, eller hur? Används KgDatas conio+.h måste också fstream inkluderas om queue ska användas. Används conio.h behövs däremot inte fstream. Då fungerar det ändå! Fortsätt med att lägga in följande kod: int x=wherex(), y=wherey(); cout << Tryck tangent ; getch(); queue<int> talserie_2; gotoxy(x,y); clreol(); cout << Kö\n\n ; for (i=0; i<10; i++) talserie_2.push(i); while (!talserie_2.empty()) cout << talserie_2.front() << ; talserie_2.pop(); cout << \n\ntalen \ poppas\ i den ordning de lades in. ; Koden är nästan lika den föregående. Skillnaden är att front() används istället för top() för att läsa element. Då läses det elements värde, som ligger främst i kön och är det element som matades in först. Man kan också läsa sista elementet i en kö, dvs det som matades in sist. Det görs med funktionen back(). Innan fler element kan läsas med front() måste främsta elementet poppas bort. Det är vad som sker här tills kön är tom. Som du ser kommer nu talen ut ur kön i den ordning de matades in. Spara. Uppgift 7 5. Ett program som använder stack Ibland är stack speciellt lämplig att använda. Det gäller ofta då ordningsföljd i något sammanhang ska kastas om. Ett exempel är instruktioner vid demontering / montering. Efter demontering kan ofta montering ske igen efter samma instruktioner bara de följs i omvänd ordning. Ett moderkortsbyte på en dator utförs genom att chassit tas bort, moderkortet lokaliseras, olika kablar lossas, processorn tas bort etc. Efter moderkortsbytet sätts datorn ihop igen efter samma instruktionerna men i motsatt ordning. Med en stack, där instruktionerna lagts in, är det lätt att vända dem så att instruktionerna kommer i omvänd ordning. Något liknande behöver göras i vårt programexempel här. Vi ska skriva ett program som kan avgöra om en textsträng är ett palindrom eller inte. Ett palindrom är en textsträng som är likadan fram- och baklänges. Exempelvis är kåk och anna exempel på korta palindrom. Då kan det vara lämpligt att använda en stack med vars hjälp vi enkelt kan vända på ordningsföljden hos bokstäverna i strängen. Om bokstäverna läggs in i en stack i följd tecken för tecken kan dessa sedan läsas i omvänd ordning. Programmet ska låta användaren mata in en sträng. Vid kontrollen av om strängen är ett

palindrom ska stora eller små bokstäver inte ha någon betydelse. Inte heller ska mellanslag göra någon skillnad. Exempelvis ska strängen Ni talar bra latin godkännas som palindrom. Nu till programexemplet! Skapa projektet Ex05_06 med cpp-filen Ex06. Lägg in följande kod i cpp-filen: // Ex05_06. Program som avgör om en sträng är ett palindrom eller inte #include <iostream> #include <string> // Behövs i Visual #include <stack> #include <conio.h> using namespace std; #include svtecken.h string bak_och_fram(string str); int main() teckenbyt(); stack<char> teckenstack; string str, str2; unsigned int i; cout << \nmata in en sträng (bryt med tomsträng): ; while (getline(cin,str) && str!= ) cout << endl << \' << str << \' är ; str2=bak_och_fram(str); for (i=0; i<str.size()/2; i++) if (str[i]!=str2[i]) break; if (i<str.size()/2) cout << inget palindrom ; else cout << ett palindrom ; cout << \n\nmata in en ny sträng (bryt med tomsträng): ; cout << \n\n ; cout << Tryck tangent ; getch(); return 0; string bak_och_fram(string str) stack<char> teckenstack; unsigned int j; for (j=0; j<str.size(); j++) teckenstack.push(str[j]); for (j=0; j<str.size(); j++) str[j]=teckenstack.top(); teckenstack.pop(); return str;

Kör programmet och testa olika ord. Om du använder blandat små och stora bokstäver eller mellanslag märker du att programmet inte klarar det ännu. Det intressanta händer i funktionen bak_och_fram() där ord som kommer in vänds. En stack deklareras och tecken efter tecken i ordet läggs på stacken med push(). Sedan läses tecknen med top() och poppas med pop(). Poppning är nödvändig för att kunna läsa nästa tecken. Observera att det är samma string-ord som används hela tiden och som returneras när vändningen är klar. Vi ska fortsätta programmet, så att även strängar med mellanslag och både små och stora bokstäver kan kontrolleras med framgång. Utöka programmet med funktionen ta_bort_och_byt_tecken(); med följande prototyp: void ta_bort_och_byt_tecken(string& str); och definition: void ta_bort_och_byt_tecken(string& str) string str2; for (unsigned int j=0; j<str.size(); j++) if (str[j]>64&&str[j]<96) str[j]=str[j]+32; else if (str[j]=='å') str[j]='å'; else if (str[j]=='ä') str[j]='ä'; else if (str[j]=='ö') str[j]='ö'; if (str[j]!=' ') str2=str2+str[j]; str=str2; Här läggs först 32 till ASCII-tecknet om tecknen är versaler. Då blir versalerna gemena tecken. Fast eftersom detta inte gäller för de svenska tecknen kontrolleras och ändras dessa separat. Tecknet läggs till den lokala variabeln str2 som på slutet tilldelas str. I main() läggs en rad till där anrop till ta_bort_och_byt() görs två gånger först med str och sedan med str2 som parameter: while (getline(cin,str) && str!= ) cout << endl << \' << str << \' är ; str2=bak_och_fram(str); ta_bort_och_byt_tecken(str); ta_bort_och_byt_tecken(str2); for (i=0; i<str.size(); i++) if (str[i]!=str2[i]) break; if (i<str.size()) cout << inget palindrom ; else cout << ett palindrom ; cout << \n\nmata in en ny sträng (bryt med tomsträng): ; Kör programmet och testa strängar som kanske är palindromer. Även strängar med de svenska tecknen kan nu kontrolleras. Uppgift 7

6. Ett program som använder queue Vi ska skriva ett program som implementerar en kö och simulerar en kö-situation. Vi väljer en telefonkö, som högst fungerar för 20 samtal. Den här begränsningen läggs in av praktiska skäl eftersom kön ska symboliseras med tal i fönstret och det inte finns plats att skriva ut fler samtal än 20, om det ska bli snyggt och enkelt. I Builder måste vi tänka på att också inkludera fstream, eftersom det behövs om conio+.h inkluderas. Men vi lägger alltså inte in fstream för att skriva eller läsa någon fil utan det beror på buggen som påtalades tidigare. Funktionerna meny(), som skriver menyn och läser menyval, samtal_in(), som låter ett samtal ställas i kön och skriv_ut(), som skriver ut telefonkön, är de funktioner som deklareras och implementeras i programmet. Lägg in projektet Ex06_06 med cpp-filen Ex06, där nedanstående kod läggs in: // Ex06_06. Program som simulerar en telefonkö #include <iostream> #include <queue> #include <conio+.h> using namespace std; #include svtecken.h #include egna_funktioner.h void meny(char& ch); void samtal_in(queue<int>& lista, int& samtalsnr); void skriv_ut(queue<int> lista); int main() teckenbyt(); queue<int> lista; char ch; int samtalsnr=1; gotoxy(20,24); cout << Telefonkön kan högst innehålla 20 samtal ; meny(ch); while (ch!='0') switch(ch) case '1': samtal_in(lista, samtalsnr); break; case '2': break; case '3': break; case '4': break; meny(ch); cout << \n\n ; return 0; void meny(char& ch) gotoxy(1,1); cout << \n Meny:\n\n 1. Nytt inkommande samtal\n\n

<< 2. Expediera ett samtal\n\n 3. Skriv ut det samtal som är först << \n\n 4. Skriv ut det samtal som är sist\n\n 0. Avsluta ; cout << \n\n\n Ange alternativ genom att trycka siffra: ; ch=getch( 01234 ); void samtal_in(queue<int>& lista, int& samtalsnr) if (lista.size()<20) lista.push(samtalsnr); skriv_ut(lista); samtalsnr++; if (samtalsnr==100) samtalsnr=1; void skriv_ut(queue<int> lista) gotoxy(1,22); clreol(); int x=42+lista.size()*2; while (!lista.empty()) x-=4; gotoxy(x, 22); cout << lista.front(); lista.pop(); Kör programmet och använd menyalternativen. I funktionen samtal_in() ovan skrivs nya samtal in i kön med push() som vi kan förvänta oss. Det som skrivs i den här simuleringen är ett heltal, som börjar med 1 och högst kan bli 99. Därefter börjar numreringen om igen med 1 som du ser i koden. Förutsättningen för att samtal ska gå att lägga in i kön är att den inte är full, dvs att antalet tidigare samtal i kön inte är större än 19. Funktionen anropar skriv_ut() för att simuleringen av inlagt samtal ska skrivas ut. I funktionen skriv_ut() rensas först eventuell tidigare utskrift på rad 22 med clreol(), positionen för utskrift av första samtalet läggs in i variabeln x. Sedan skrivs telefonkön ut centrerat på skärmen med hjälp av gotoxy(). Utskriften av samtalsnumren skrivs åt vänster så att det samtal som ligger först i kön skrivs längst åt höger. Efter utskrift av element måste de poppas. Nu ska även funktionen samtal_ut() läggas in. Lägg in: prototypen: void samtal_ut(queue<int>& lista); och implementeringen: void samtal_ut(queue<int>& lista) if (!lista.empty()) lista.pop(); skriv_ut (lista);

Koden i samtal_ut() är enkel. Först poppas främsta elementet och sedan visas det med skriv_ut(). Lägg in aktivering av menyvalet i main(): case '2': samtal_ut(lista); break; Kör programmet och prova även att beta av samtal i listan. Även de två resterande menyalternativen ska implementeras genom funktioner som läggs in: Prototyper: void skriv_ut_forsta(queue<int> lista); void skriv_ut_sista(queue<int> lista); Definitioner: void skriv_ut_forsta(queue<int> lista) int x=38+lista.size()*2; gotoxy(2,18); cout << Först kön: << lista.front(); setcolor(lightgreen); gotoxy(x,22); cout << lista.front(); delay(1000); setcolor(lightgray); gotoxy(2,18); clreol(); void skriv_ut_sista(queue<int> lista) int x=42+lista.size()*2-lista.size()*4; gotoxy(2,18); cout << Sist i kön: << lista.back(); setcolor(yellow); gotoxy(x,22); cout << lista.back(); delay(1000); setcolor(lightgray); gotoxy(2,18); clreol(); Aktivera alternativen i menyn: case '3': skriv_ut_forsta(lista); break; case '4': skriv_ut_sista(lista); Kör programmet och pröva även de två nyinlagda alternativen. I funktionerna ovan, som är mycket lika, skrivs de nummer som ligger först respektive sist i kön ut. Först bestäms rätt x-koordinat och därefter skrivs text med nummer ut på rad 18. Texten raderas efter en kort stund. Dessutom färgas numret i kösimuleringen på rad 22. Det nummer som är först färgas grönt och det nummer som är sist färgas gult. Spara. Uppgift 8 7. Glosträningsprogram med stack och queue Låt oss avsluta kapitlet med ett program, som använder både stack och queue. Det är frestande att använda stack och queue i program eftersom det ofta är så enkelt. I det program vi ska bygga i det här avsnittet skulle kanske hellre vector eller list ha använts, men vi ska använda queue

och stack. Eftersom programmet ska ha vit bakgrund med svart textfärg men även lite grön och röd textfärg inkluderas conio+.h. Skapa projektet Ex07_06 med cpp-filen Ex06. Lägg in koden nedan i cpp-filen: // Ex07_06. Glosträningsprogram #include <iostream> #include <string> // Behövs i Visual #include <fstream> // Behövs i Builder för att köra programmet #include <stack> #include <queue> #include <conio+.h> using namespace std; #include svtecken.h #include egna_funktioner.h struct Ordpar string sv_ord; string en_ord; ; void mata_in(queue<ordpar>& ordlista); void skriv_ut(queue<ordpar> ordlista); int main() teckenbyt(); queue<ordpar> ordlista; srand(time(0)); setcolor(black, BACKGROUND_WHITE); clrscr(); mata_in(ordlista); cout << \n\nföljande svenska och engelska ord matades in:\n\n ; skriv_ut(ordlista); cout << \n\n ; cout << Tryck tangent ; getch(); return 0; void mata_in(queue<ordpar>& ordlista) Ordpar ordpar; cout << \n Mata in det svenska ordet: ; getline(cin, ordpar.sv_ord); while (ordpar.sv_ord!= ) cout << Mata in det engelska ordet: ; getline(cin, ordpar.en_ord); ordlista.push(ordpar); cout << \n Mata in det svenska ordet: ; getline(cin, ordpar.sv_ord); void skriv_ut(queue<ordpar> ordlista)

Ordpar ordpar; while (!ordlista.empty()) ordpar=ordlista.front(); ordlista.pop(); cout << ordpar.sv_ord << << ordpar.en_ord << endl; Kör programmet och mata in samhörande svenska och engelska ord. Det här programmet använder en kö av struct. Strukturen definieras i programmets början och heter Ordpar och består av string-variablerna sv_ord och en_ord. I början av main() deklareras en queue-variabel av Ordpar, ordlista, som ska innehålla de ordpar som matas in. I funktionen mata_in() matar användaren in ordparen som pushas in i kön. Funktionen skriv_ut() fungerar som tidigare skriv_ut-funktioner. Så länge ordlistkön inte är tom läses främsta ordparet med front() och skrivs ut. Efter att ordparet poppats bort med pop() kan nästa ordpar läsas och skrivas. Eftersom ingen referensparameter finns sker poppningen lokalt. Ordlistan är helt intakt i main(). Tanken inställer sig osökt, att det här programmet enkelt skulle kunna utvecklas till ett enkelt glosprogram. Man matar in samhörande ord på svenska och engelska och sparar dem i en fil. Det ordpar som är främst i kön läses, det svenska ordet skrivs ut och användaren ska då försöka översätta det. Svaret läses och rättas. Ordparet tas bort med pop() och nästa kan läsas. När kön är slut presenteras resultatet och om man vill ska man kunna göra om eller fortsätta med en ny övning. Men helst ska ordlistan förstås blandas först. Det är inte lätt att använda gängse metoder där element slumpas och sedan får byta plats, eftersom ingen indexering kan göras i en kö. Men en bra start skulle kunna vara att först byta ordningsföljd på ordparen i ordlista med hjälp av en stack, sedan använda slumpfunktionen rand() för att pusha ordparen antingen till en hjälpkö eller tillbaka in i ordlistan igen. Ordpar efter ordpar läggs alltså slumpvis in i hjälpkön eller ordlistan. Detta får pågå tills ordlistan är tom och alla ordpar har flyttats över till hjälpkön. Då borde ordparen i hjälpkön ha fått en sådan oordning att det i alla fall räcker för vårt ändamål. Avslutningsvis tilldelas hjälpkön till ordlista och vi kan kontrollera om det fungerat så bra, att funktionen verkligen kan ges namnet blanda(). Låt oss göra ett försök! Vi lägger in prototypen till funktionen: void blanda(queue<ordpar>& ordlista); Funktionen implementeras enligt nedan. Lägg in funktionen: void blanda(queue<ordpar>& lista) Ordpar ordpar; queue<ordpar> kopia; stack<ordpar> stk; while (!lista.empty()) stk.push(lista.front()); lista.pop(); while (!stk.empty()) lista.push(stk.top()); stk.pop(); while (!lista.empty()) ordpar=lista.front(); lista.pop(); if (rand()%2==0) lista.push(ordpar); else kopia.push(ordpar); lista=kopia;

Lägg in anrop till funktionen efter inmatningen i main():...kod som tidigare mata_in(ordlista); blanda(ordlista); cout << \nföljande svenska och engelska ord matades in:\n\n ; skriv_ut(ordlista); kod som tidigare... Kör programmet. I funktionen blanda() deklareras en lokal kö kopia och stack stk. Först läggs alla ordparen i ordlista på stacken stk och sedan tillbaka igen i ordlista. Det medför att ordningen i ordlista nu är den motsatta. Därefter följer en while-sats där ordparen antingen läggs in i kopia eller i ordlista igen. Detta pågår tills ordlista är tom. Satsen: ordlista = kopia; ordnar så att alla ordparen läggs tillbaka i ordlista igen - fast nu blandade förhoppningsvis! För att testa resultatet av blandningen kan exempelvis 10 ordpar matas in och en heltalsvektor med 10 element deklareras och nollställas. Därefter kan 10 000 slumpningar göras och resultatet läggas in i vektorn. Om vektorn ges namnet slumptal läggs antalet gånger första elementet har slumpats först in i slumptal[0], antalet gånger andra elementet har slumpats först in i slumptal[1] osv. Efter slumpningarna skrivs elementen i slumptal ut och resultatet kan studeras på skärmen. Dessutom kan ordparen skrivas ut i följd ett antal gånger så, att man ser att ändring sker varje gång. Vi lämnar en kontroll enligt ovan till läsaren, men resultatet ger troligtvis som resultat att slumpningen i funktionen blanda() kan anses tillfredställande. Vi ger ett utkast till funktionen kor_ovning(), där översättningen ska göras. Lägg in prototypen: void kor_ovning(queue<ordpar> ordlista); och implementeringen: void kor_ovning(queue<ordpar> ordlista) Ordpar ordpar; string svar; int x, y, antal_ratt=0; clrscr(); while (!ordlista.empty()) ordpar=ordlista.front(); ordlista.pop(); cout << \n Översätt \' << ordpar.sv_ord << \' till engelska: ; x=wherex(); y=wherey(); getline(cin, svar); gotoxy(x+svar.size()+2,y); if (svar==ordpar.en_ord) setcolor(green, BACKGROUND_WHITE); cout << Rätt ; antal_ratt++; else setcolor(lightred, BACKGROUND_WHITE); cout << Fel. Rätt ord: << ordpar.en_ord; setcolor(black, BACKGROUND_WHITE);

Komplettera med anrop av kor_ovning() i main(). Lägg in kod enligt följande: int main() teckenbyt(); queue<ordpar> ordlista; srand(time(0)); setcolor(black, BACKGROUND_WHITE); clrscr(); mata_in(ordlista); blanda(ordlista); kor_ovning(ordlista); cout << \n\n ; cout << Tryck tangent ; getch(); return 0; Kör programmet och testa det. I kor_ovning() används en while-slinga tills ordlista är tom. I varje varv poppas nämligen det främsta ordet. Före getline() används funktionerna wherex() och wherey() för att lagra inmatningspositionen. Sedan bestäms utskriftspositionen med gotoxy() så att Rätt eller Fel skrivs på samma rad som inmatningen skett på och i rätt position. Före utskriften sätts textfärg och bakgrundsfärg med den överlagrade setcolor() från kapitel 5 och efter utskriften sätts textfärgen tillbaka till svart igen. Bilden nedan visar körning av programmet. Här ses hur programmet ser ut då KgDatas setcolor() med både textfärg och bakgrundsfärg används. Uppgift 9, Uppgift 10

Nedan har de få funktioner som finns i stack och queue samlats i en tabell: Funktionens namn Gör följande Finns i size() Returnerar längden stack, queue push(element) Lägger till element stack, queue top() Läser element som är överst på stacken stack front() Läser element som är först i kön queue back() Läser element som är sist i kön queue empty() Returnerar true om inga element finns stack, queue = Tilldelar en hel stack eller kö stack, queue ==!= <= > >= Används för jämförelse stack, queue Sammanfattning av kapitel 6: Vi har: testat funktioner till list i ett program jämfört list med vector använt skrivit ett funktionsuppbyggt program där struct använts i en lista sorterat lista med struct diskuterat stack och kö och givit exempel på användning skrivit program med stack och queue använt queue i program för att vända på en ordningsföljd simulerat en kö i ett program använt stack och queue för att skriva början till ett glosträningsprogram sammanfattat funktioner i vector och list och i stack och queue

Uppgifter: 1. Skriv ett program, som deklarerar en list av int, och där ett antal sådana läggs in i listan. Utskrift av listan ska ske. Därefter ska ytterligare tre tal läggas till listan: ett i början, ett i slutet och ett på en plats mitt i listan. Ny utskrift av talen ska ske. 2. Skriv ett program där string-strängar ska matas in till en lista. När inmatningen är klar ska listan sorteras i fallande ordning. Sortering av svenska tecknen behöver inte fungera. Efter sortering ska listan skrivas ut. 3. Skriv funktioner så att alternativen 3 och 5, Radera konto och Radera alla konton, fungerar i Ex02_06. 4. En funktion, som saknas i Ex02_06, är void infoga(list<konto>& kontolista). Den behövs för att menyalternativ 4 ska fungera. Skriv funktionen och se till att den fungerar i programmet. 5. Sorteringen i Ex03_06 fungerar inte för de speciella svenska tecknen. Ändra funktionen sortera() så att sorteringen även fungerar på svenska. Det kan exempelvis göras genom att tecknen i strängar före jämförelser byts enligt följande: å, ä och ö byts mot tecken 123, 124 och 125 och tecken Å, Ä och Ö mot tecknen 91, 92 och 93. Byte tillbaka måste naturligtvis också göras där det behövs. Liknande byte av tecken har tidigare gjorts i Uppgift 6 i Kapitel 4. 6. Komplettera programmet Ex03_06 så att även menyalternativ 7 fungerar. Sökning på ett namn ska ge utskrift av den personens konto. 7. Då Olle från Västerås skulle göra en Göteborgsresa, beställde han hotellrum på Internet. Han kunde då skriva ut en vägbeskrivning för bil, som till hans förtjusning tog hand om alla problem med att hitta till Göteborg och till hotellet. Så här stod det: 1. Kör Vasagatan ungefär 2 km 2. Ta av vid Rocklundamotet 3. Kör E18 ungefär 10 mil 4. Ta av i Örebro 5. Kör E20 ungefär 25 mil 6. Ta av vid Källtorpsmotet 7. Kör Härlandagatan 200 m Skriv ett program, som vänder på vägbeskrivningen. Den ska Olle kunna använda för hemfärden. Använd en stack. 8. Använd filen med text om Pippi Långstrump, som användes första gången i uppgift 5 i Kap 3. Texten har lagts in på nytt på nästa sida. Skriv ett program som läser filen och lagrar de ord i texten som har en viss längd eller är längre. Programmet ska läsa filen och lagra orden i en kövariabel efter att först ha frågat efter hur långa orden minst ska vara. Orden ska skrivas ut först då lagringen är klar. Gör programmet upprepningsbart.

Efter honom kom Pippi. Hon bar hästen. Då gick det ett sus genom alla kurrekurredutterna. Visserligen hade de hört talas om Pippi och hennes kolossala styrka, men det var någonting helt annat att se det i verkligheten. Tommy och Annika traskade beskedligt i land de också, och det gjorde hela besättningen med, men just då hade kurrekurredutterna inte ögon för någon annan än Pippi. Kapten Långstrump lyfte upp henne och ställde henne på sina axlar, för att de riktigt skulle kunna se henne, och då gick det om igen ett sus genom folkhopen. Men strax efteråt lyfte Pippi upp kapten Långstrump på sin ena axel och hästen på den andra, och då steg suset nästan till en orkan. Hela Kurrekurreduttöns befolkning uppgick inte till mer än 126 människor. "Det är ungefär lagom många undersåtar att ha", sa kung Efraim. "Fler kan man inte hålla reda på." Allihop bodde i små hemtrevliga hyddor bland palmerna. Den största och finaste hyddan tillhörde kung Efraim. Besättningsmännen på 'Hoppetossa' låg för ankar i den lilla viken. Det gjorde hon förresten nästan jämt numera. Bara ibland blev det nödvändigt med en expedition till en ö 50 mil norrut. Där fanns nämligen en affär, i vilken man kunde köpa snus åt kapten Långstrump En mycket fin, nybyggd liten hydda under en kokospalm var avsedd för Pippi. Tommy och Annika fick god plats där också. Men innan de fick gå in i hyddan och tvätta resdammet av sig, ville kapten Långstrump visa dem en sak. Han grep Pippi i armen och förde henne ner till stranden igen 9. Förbättra Ex07_06 så att programmet blir mer användarvänligt. Lägg in meny och filfunktioner för läsning och skrivning av ordlistor. En pågående övning ska kunna avbrytas eller köras på nytt om användaren så vill. Möjlighet att träna på de ord man inte klarat av ska finnas då en övning är slut. Det ska även vara möjligt att välja olika ordlistor. 10. Per och Lisa vill bjuda sina vänner på ett party med bjudningskort och allt. De ber dig, som kan programmera, att skriva ett program där de ska kunna mata in varsin lista med namn på personer de vill bjuda. Programmet ska slå samman listorna och skriva ut namnet på de personer som ska bjudas. Listan, som ska vara sorterad efter förnamn, ska kunna användas för att skriva ut inbjudningskort och bör därför inte innehålla samma person mer än en gång. Det händer annars lätt eftersom de har en del gemensamma vänner. Det finns två användbara funktioner som du kan använda: merge(), som sätter samman den lista som anropar funktionen med listan i parentesen. Ex: lista_1.merge(lista_2); sätter ihop lista_1 med lista_2, som töms. unique(), som tar bort dubbletter ur den lista som anropar funktionen, som är av typ void. Ex: lista_1.unique(); tar bort dubbletter från lista_1. Observera att om funktionerna endast fungerar med sorterade listor. Gör programmet i första hand så att det fungerar utan svenska tecken. I andra hand ordnar du dessutom sortering efter svenska tecken.