Algoritmen en Datastructuren

Slides:



Advertisements
Verwante presentaties
Objectgeoriënteerd Programmeren in C++
Advertisements


Vervolg C Hogeschool van Utrecht / Institute for Computer, Communication and Media Technology 1 Een programma opbouwen.
HM-ES-th1 Les 9 Hardware/Software Codesign with SystemC.
Algoritmen en Datastructuren (ALDAT)
JQuery en ASP.NET Bart De Meyer.
Conditional Clauses If-zinnen.
Real-Time Systems (RTSYST) Week C++ concurrent programmeren C++ heeft sinds C++11 een standaard library voor concurrent programmeren. Alternatieve.
Ronde (Sport & Spel) Quiz Night !
Programmeren in Java met BlueJ
EVMINX4 Week 3 Algoritmen en Datastructuren (ALDAT)
Gestructureerd programmeren in C
Vervolg C Hogeschool van Utrecht / Institute for Computer, Communication and Media Technology 1 Onderwerpen voor vandaag Gelinkte lijsten Finite State.
MagentaPurpleTeal PinkOrangeBlue LimeBrown RedGreen Introductie C# /.NET
PROS2 Les 11 Programmeren en Software Engineering 2.
GESPRG Les 14 Gestructureerd programmeren in C. 174 Details! The devil is in the details.
Datastructuren Analyse van Algoritmen en O
Introduction multimedia. convergence standards retrieval applications & technology.
Omgevingen zijn dan geïmplementeerd als Symbol Tables. Symbol Table mapt een symbool met een Binding Meerdere noties van binding –Meerdere manieren te.

HM-ES-th1 Les 1 Hardware/Software Codesign with SystemC.
Modula vs Java MODULE Show; CONST PI = ; TYPE PointRc = RECORD x,y : INTEGER; speed : REAL; angle : REAL; END; VAR a,b : PointRc; BEGIN.
1 Datastructuren Lijstjes (Stacks & Queues) Onderwerp 7.
1/1/ / faculty of Computer Science eindhoven university of technology 5JJ20:Computerarchitectuur 2M200:Inleiding Computersystemen Sessie 7(2): Vertalen.
Neurale Netwerken Kunstmatige Intelligentie Rijksuniversiteit Groningen April 2005.
Algoritmiek Arrays: wat zijn dat en wat kun je ermee? Loops: hoe hou je ze in bedwang? Hoorcollege 6 - Ma. 9 okt L.M. Bosveld-de Smet.
Inleidend probleem Data structuur (hiërarchie van classes)
Algoritmen en Datastructuren (ALDAT) EVMINX4 Week 6.
Algoritmen en Datastructuren (ALDAT) EVMINX4 Dagdeel 2.
MICPRG Les 11 Microcontroller Programmeren in C. 112 Datastructuren in C Werkgeheugen (PC en microcontroller): Statische datastructuren (vaste grootte):
GESPRG Les 8 Gestructureerd programmeren in C. 101 Array Meerdere variabelen van hetzelfde type kun je samennemen in één array variabele. Stel in een.
Real-Time Systems (RTSYST) Week IPC inter process communication Shared variabele based (H5) Message based (H6) Kan ook gebruikt worden in systemen.
GESPRG Les 12 Gestructureerd programmeren in C. 152 Huiswerk Uitwerking void reverse(int a[], int n) { int first = 0, last = n - 1; while (first < last)
Netwerk Algorithms: Shortest paths1 Shortest paths II Network Algorithms 2004.
Optuigen van datastructuren
Array nDeclaratie nCreatie nOpvragen nWijzigen nLengte String [ ] a; a = new String[10]; ……a[5]…… a[5] = ……; …a.Length… …is eigenlijk overbodig! List a;
Hoorcollege 8 Game object structuren. Arrays in games Grid-gebaseerd speelveld (zoals Tetris) Lijst van spelers Lijst van inventory items Lijst van alle.
Hoorcollege 7 Collections, arrays. Programma ‘Snowflakes’ Sneeuwvlok object.
Werken aan Intergenerationele Samenwerking en Expertise.
1 Van Harvard naar MIPS. 2 3 Van Harvard naar MIPS Microprocessor without Interlocked Pipeline Stages Verschillen met de Harvard machine: - 32 Registers.
PLAYBOY Kalender 2006 Dit is wat mannen boeit!.
Algoritmiek Strings & Stringmanipulaties; Controle Structuren; Floating-point notation. Hoorcollege 4 - Ma. 25 sept L.M. Bosveld-de Smet.
DB&SQL8- 1 VBA Visual Basics for Applications: eigen Office versie vanaf Office2000 gelijk voor alle applicaties Programmeren onder meer nodig voor Het.
1 Datastructuren Introductie tot de programmeeropgaven in C++ Jan van Rijn
JAVA1 H 22. COLLECTIONS FRAMEWORK. 1. INLEIDING. Collections framework Is een verzameling van data structuren, interfaces en algoritmen Meest voorkomende.
Hogeschool HZ Zeeland 19 augustus 2003augustus 2003 Data Structuren & Algoritmen Week 3.
Computertechniek 2 – ARM assembler Hogeschool van Utrecht / Institute for Computer, Communication and Media Technology 1  D3EEMS1  programmed I/O: de.
Computertechniek Hogeschool van Utrecht / Institute for Computer, Communication and Media Technology ; PIC assember programeren 1 Les 3 - onderwerpen Het.
KPRES1 : C vervolg Hogeschool van Utrecht / Institute for Computer, Communication and Media Technology Les 2 sheet 1 Wat gaan we doen:  Een (vaste) melodie.
Vervolg C Hogeschool van Utrecht / Institute for Computer, Communication and Media Technology 1 Onderwerpen voor vandaag GUI  command line redirection.
Hoofdstuk 2 Java. Soorten Java-programma’s nJava Applet programma “leeft” op een WWW-pagina nJava Application programma heeft een eigen window nJavascript.
ZijActief Koningslust 10 jaar Truusje Trap
Internetapplicaties - IV Collecties 1 Internetapplicaties Deel 4: Java hulpklassen: Collecties.
ECHT ONGELOOFLIJK. Lees alle getallen. langzaam en rij voor rij
Shortest path with negative arc-costs allowed. Dijkstra?
TOPIC O: Pointers | pag. 1 Pointer = adres in het geheugen, is zelf geen geheugen! Expliciet geheugen aanvragen vóór gebruik.
Hoofdstuk 5 Interactie. Controls Form Label Button Label TextBox.
De financiële functie: Integrale bedrijfsanalyse©
Computertechniek Hogeschool van Utrecht / Institute for Computer, Communication and Media Technology 1 C programmeren voor niet-C programmeurs les 7 onze.
C++ C++ als een verbetering van C Abstracte datatypen met classes Constructoren en destructoren Subklassen binding van functies 1.
Computertechniek Hogeschool van Utrecht / Institute for Computer, Communication and Media Technology 1 C programmeren voor niet-C programmeurs les 2 definitie.
1 Zie ook identiteit.pdf willen denkenvoelen 5 Zie ook identiteit.pdf.
ZijActief Koningslust
Tircms03-p les 4 Klassen. Abstracte datatypes in C struct stack { char info[100]; int top; }; void reset(stack *s) { s->top = -1; } void push(stack *s,
1 XSLT processing & control Datamodellering 2006.
Tircms03-p les 1 C++ voor C-kenners Voor Technische Informatica.
1 PI1 week 9 Complexiteit Sorteren Zoeken. 2 Complexiteit van algoritmen Hoeveel werk kost het uitvoeren van een algoritme (efficiëntie)? –tel het aantal.
 C++ heeft een inheritance mechanisme  Manier om functionaliteit te ‘erfen’ van een parrent class ◦ Polymorphisme ◦ Zoals we het ook in C# kennen.
Tinpro015b-les 1 C++ voor C-kenners Voor Technische Informatica.
Transcript van de presentatie:

Inhoud Week 1 Week 2 Week 3 Week 4 Week 5 Week 6 Week 7

Algoritmen en Datastructuren ALGODS Week 1

Inhoud ALGODS Onderwerpen: Werkvormen: Algoritmen en Datastructuren standaard C++ library (vroeger: STL) Diverse toepassingen van algoritmen en datastructuren Kortste pad en spelletjes Werkvormen: Theorie (2 uur/week theorie) in week 1 t/m 7 Practicum (1 uur/week begeleid en 1 uur/week onbegeleid) Zelfstudie en toetsing (4 uur/week) in week 1 t/m 8 Reparatie in week 9 of 10 2

Leermiddelen Boeken Dictaat (zelf dubbelzijdig afdrukken!) Thinking in C++ 2nd Edition, Volume 1 + 2, Bruce Eckel Praktisch UML, 5de editie, Warmer en Kleppe Dictaat (zelf dubbelzijdig afdrukken!) Aanvullingen op theorie Extra voorbeelden Handouts (in laatste weken) Blackboard en http://bd.eduweb.hhs.nl/algods/ Studiewijzer met uitgebreide planning Dictaat Practicumopdrachten + uitgebreide practicumhandleiding Sourcecode van alle voorbeelden Sheets Links 3

Voorbeeld Do you remember MICPRG? Statische datastructuur: struct deelnemer { int punten; char naam[80]; }; struct stand { int aantalDeelnemers; deelnemer lijst[100]; }; stand s; De nadelen van het gebruik van de ingebouwde datastructuren struct en array zijn: de grootte van de array's lijst en naam moet bij het vertalen van het programma bekend zijn en kan niet aangepast worden (=statisch). elke deelnemer neemt evenveel ruimte in onafhankelijk van de lengte van zijn naam (=statisch). het verwijderen van een deelnemer uit de stand is een heel bewerkelijke operatie. 4

Voorbeeld Do you remember OGOPRG? Dynamische datastructuur: class Deelnemer { public: Deelnemer(const string& n, int p); int punten() const; const string& naam() const; void verhoogpunten(int p); private: int pnt; string nm; }; class Stand { public: void voegtoe(const Deelnemer& d); void verwijder(const string& n); int punten(const string& n) const; void verhoogpunten(const string& n, int p); vector<deelnemer>::size_type aantalDeelnemers() const; private: vector<Deelnemer> lijst; }; Stand s; Welke andere dynamische datastructuren zijn er? Hoe werken dynamische datastructuren eigenlijk? 5

Recursieve datastructuren Lijst leeg of element met pointer naar lijst Stamboom persoon met pointer naar stamboom (van vader) en pointer naar stamboom (van moeder) 6

‘76 boek van Niklaus Wirth: Algorithms + Datastructures = Programs 7

Klassieke datastructuren Klassieke datastructuren kunnen m.b.v. OOP technieken als herbruikbare componenten worden geïmplementeerd. Er zijn diverse component- bibliotheken verkrijgbaar: STL (Standard Template Library) Opgenomen in ISO/ANSI C++98 std (sept 1998) Aanwezig in Microsoft Visual C++ 2010 en GCC. Boost (http://www.boost.org/) Zeer uitgebreid. Een aantal boost onderdelen zijn opgenomen in ISO/ANSI C++11 std (aug 2011). Aanwezig in GCC en Microsoft Visual C++ 2012 (niet in Microsoft Visual C++ 2010). 8

Datastructuren Ding om data “gestructureerd” in op te slaan. Een template is erg geschikt voor het implementeren van een datastructuur. Basisbewerkingen: insert, remove, find empty, full, size Een bepaalde datastructuur kan op verschillende manieren geïmplementeerd worden. Een Abstracte Base Class per datastructuur maakt gebruik onafhankelijk van de implementatie. 9

Datastructures Stack Queue Vector Sorted vector Linked List Sorted list Binary Tree Search tree Hash Table Priority Queue (Binary Heap) 10

Big O notation De big O notatie wordt gebruikt om de executietijd en het geheugengebruik van algorithmen met elkaar te vergelijken. De O staat voor “order of magnitude”. f(n)=O(n2) betekent dat functie f(n) “van boven” asymptotisch begrensd wordt door g(n)=n2. Dit betekent dat f(n)  a·n2 voor grote waarden van n. Waarbij a  0 (je mag a zelf kiezen). 11

Big O notation voorbeeld Wat is de big O notatie voor: f(n) = 2n3 + 4n + 2 log2 n + 100. f(n) = 4 log2 n. f(n) = log10 n. Bedenk: log10 n = log2 n / log2 10. f(n) = 1000. f(x) = (10x4 + 4x2) / (5x3 + 12x2 + 7x). = O(n3) = O(log n) = O(log n) = O(1) = O(x) 12

Big O notation voorbeeld Wat is de executietijd van het volgende algoritme in big O notatie: T(n) = O(n) int max(const vector<int>& v) { vector<int>::size_type n = v.size(); assert(n > 0); int max = v[0]; for (vector<int>::size_type i = 1; i < n; ++i) { if (v[i] > max) { max = v[i]; } return max; Kan het beter ? … als je v.size() processoren hebt ? … als de array al gesorteerd is ? 13

Big O notation voorbeeld C++11 int max(const vector<int>& v) { assert(v.size() > 0); auto max = v[0]; for (auto elm: v) { if (elm > max) { max = elm; } return max; auto-typed variables Wel beschikbaar in VC++ 2010 Wel beschikbaar in GCC 4.4 (of hoger) Range-based for Niet beschikbaar in VC++ 2010 Wel beschikbaar in VC++ 2012 Wel beschikbaar in GCC 4.6 (of hoger) met optie –std=c++0x of –std=c++11 14

Big O notation voorbeeld C++11 int max(const vector<int>& v) { assert(v.size() > 0); auto max = v[0]; for (decltype(v.size()) i = 1; i < v.size(); ++i) { if (v[i] > max) { max = v[i]; } return max; auto-typed variables en declared type of an expression Wel beschikbaar in VC++ 2010 Wel beschikbaar in GCC 4.4 (of hoger) 15

Big O notation voorbeeld Wat is de executietijd van het volgende algoritme in big O notatie: int maxprod(const vector<int>& v) { auto n = v.size(); assert(n > 0); auto maxp = v[0] * v[0]; for (decltype(n) i = 0; i < n; ++i) { for (decltype(n) j = i; j < n; ++j) { if (v[i] * v[j] > maxp) { maxp = v[i] * v[j]; } return maxp; T(n) = O(n2) Kan het beter ? 16

Big O notation voorbeeld Wat is de executietijd van het volgende algoritme in big O notatie: Maximum van alle mogelijke producten is max * max int maxprod(const vector<int>& v) { auto n = v.size(); assert(n > 0); auto max = v[0]; for (decltype(n) i = 0; i < n; ++i) { if (v[i] > max) { max = v[i]; } return max * max; T(n) = O(n) 17

Big O notation Je ziet dat een O(n2) algoritme niet bruikbaar is voor hele grote hoeveelheden data en dat een O(10n) algoritme sowieso niet bruikbaar is. 18

Bekende datastructuren 19

Bekende datastructuren (1) 20 Heeft alleen maar nadelen!

Bekende datastructuren (2) 21

Algoritmen en Datastructuren ALGODS Week 2

Stack LIFO (Last In First Out) buffer Memberfuncties: slechts op 1 plaats toegankelijk Memberfuncties: void push(const T& t) void pop() const T& top() const Voorbeeld van gebruik: expressie evaluator insert O(1) remove O(1) find O(1) 23

ADT Stack #ifndef _TISD_Bd_Stack_ #define _TISD_Bd_Stack_ template <typename T> class Stack { public: Stack() {} virtual ~Stack() {} virtual void push(const T& t) = 0; virtual void pop() = 0; virtual const T& top() const = 0; virtual bool empty() const = 0; virtual bool full() const = 0; private: // Voorkom toekennen en kopiëren void operator=(const Stack&); Stack(const Stack&); }; #endif 24

ADT Stack C++11 #ifndef _TISD_Bd_Stack_ #define _TISD_Bd_Stack_ template <typename T> class Stack { public: Stack() = default; virtual ~Stack() = default; virtual void push(const T& t) = 0; virtual void pop() = 0; virtual const T& top() const = 0; virtual bool empty() const = 0; virtual bool full() const = 0; // Voorkom toekennen en kopiëren void operator=(const Stack&) = delete; Stack(const Stack&) = delete; }; #endif 25

Toepassingen van stacks Balanced symbol checker A simple calculator Een eenvoudige calculator is een goed te (her)gebruiken component. Denk aan numerieke invoervelden. 26

Balance (1 van 2) // Contoleer op gebalanceerde haakjes. // Invoer afsluiten met een punt. #include <iostream> #include "stacklist.h" // zie dictaat using namespace std; int main() { StackWithList<char> s; char c; cin.get(c); while (c != '.') { if (c == '(' || c == '{' || c == '[') { s.push(c); } else { if (c == ')' || c == '}' || c == ']') { if (s.empty()) { cout << "Fout" << endl; 27

Balance (2 van 2) char d = s.top(); s.pop(); if (d == '(' && c != ')' || d == '{' && c != '}' || d == '[' && c != ']') { cout << "Fout" << endl; } cin.get(c); if (!s.empty()) { return 0; 28

Postfix Wij zijn gewend infix notatie te gebruiken voor het noteren van expressies. Er bestaat nog een andere methode: reverse polish notation (RPN) of postfix genoemd. Prefix: operator operand operand Infix: operand operator operand Postfix: operand operand operator Voordelen postfix t.o.v. infix: Geen prioriteitsregel nodig Meneer Van Dale Wacht Op Antwoord. (Oud) Hoe Moeten Wij Van De Onvoldoendes Afkomen? (Modern) Geen haakjes nodig Eenvoudiger te bereken m.b.v. Stack We zullen eerst een postfix calculator maken en daarna een infix naar postfix convertor. 29

Postfix calculator (1 van 2) // Evalueer postfix expressie. Invoer afsluiten met =. #include <iostream> #include <cctype> #include "stacklist.h" // zie dictaat using namespace std; int main() { StackWithList<int> s; char c; int i; cin >> c; while (c != '=') { if (isdigit(c)) { cin.putback(c); cin >> i; s.push(i); } 30

Postfix calculator (1 van 2) else if (c == '+') { int op2 = s.top(); s.pop(); int op1 = s.top(); s.pop(); s.push(op1 + op2); } else if (c == '*') { s.push(op1 * op2); else cout << "Fout" << endl; cin >> c; cout << "=" << s.top() << endl; s.pop(); if (!s.empty()) cout << "Fout" << endl; cin.get(); return 0; 31

Infix  Postfix Gebruik een stack met karakters. Lees karakter voor karakter in. Als een ingelezen karakter geen haakje of operator is dan kan dit meteen worden doorgestuurd naar de uitvoer. Een haakje openen wordt altijd op de stack geplaatst. Als we een operator inlezen dan moeten we net zo lang operatoren van de stack halen en doorsturen naar de uitvoer totdat we: een operator op de stack tegenkomen met een lagere prioriteit of een haakje openen tegenkomen of totdat de stack leeg is. Daarna moet de ingelezen operator op de stack worden geplaatst. Als we een haakje sluiten inlezen dan moeten we net zo lang operatoren van de stack halen en doorsturen naar de uitvoer totdat we een haakje openen op de stack tegenkomen. Dit haakje openen moet wel van de stack verwijderd worden maar wordt niet doorgestuurd naar de uitvoer. Als we einde van de invoer bereiken moeten we alle operatoren van de stack halen en doorsturen naar de uitvoer. 32

Stack implementations Een stack kan op verschillende manieren geïmplementeerd worden: d.m.v. een array (of vector). d.m.v. een gelinkte lijst. 33

Stack met array (1 van 4) #ifndef _TISD_Bd_StackWithArray_ #define _TISD_Bd_StackWithArray_ #include "stack.h" // zie dictaat template <typename T> class StackWithArray: public Stack<T> { public: explicit StackWithArray(size_t size); virtual ~StackWithArray(); virtual void push(const T& t); virtual void pop(); virtual const T& top() const; virtual bool empty() const; virtual bool full() const; private: T* a; // pointer naar de array size_t s; // size van a (max aantal elementen op de stack) size_t i; // index in a van de eerste lege plaats }; 34

Stack met array (1 van 4) C++11 #ifndef _TISD_Bd_StackWithArray_ #define _TISD_Bd_StackWithArray_ #include "stack.h" // zie dictaat template <typename T> class StackWithArray: public Stack<T> { public: explicit StackWithArray(size_t size); virtual ~StackWithArray() override; virtual void push(const T& t) override; virtual void pop() override; virtual const T& top() const override; virtual bool empty() const override; virtual bool full() const override; private: T* a; // pointer naar de array size_t s; // size van a (max aantal elementen op de stack) size_t i; // index in a van de eerste lege plaats }; Explicit override voorkomt overload (per ongeluk door bijvoorbeeld spelfout) 35

Stack met array (2 van 4) template <typename T> StackWithArray<T>::StackWithArray(size_t size): a(0), s(size), i(0) { if (s <= 0) { std::cerr << "Stack size should be >0" << std::endl; s = 0; } else { a = new T[s]; StackWithArray<T>::~StackWithArray() { delete[] a; 36

Stack met array (3 van 4) template <typename T> void StackWithArray<T>::push(const T& t) { if (full()) std::cerr << "Can't push on an full stack" << std::endl; else a[i++] = t; } template <typename T> void StackWithArray<T>::pop() { if (empty()) std::cerr << "Can't pop an empty stack" << std::endl; --i; template <typename T> const T& StackWithArray<T>::top() const { if (empty()) { std::cerr << "Can't top an empty stack" << std::endl; std::exit(-1); // no valid return return a[i - 1]; 37

Stack met array (4 van 4) template <typename T> bool StackWithArray<T>::empty() const { return i == 0; } template <typename T> bool StackWithArray<T>::full() const { return i == s; #endif 38

Stacktest #include <iostream> #include "stackarray.h" using namespace std; int main() { StackWithArray<char> s(32); char c; cout <<"Type een tekst, sluit af met ." << endl; cin.get(c); while (c != '.') { s.push(c); } while (!s.empty()) { cout << s.top(); s.pop(); cin.get(); cin.get(); return 0; 39

Stack met lijst (1 van 3) #include "stack.h" template <typename T> class StackWithList: public Stack<T> { public: StackWithList(); virtual ~StackWithList(); virtual void push(const T& t); virtual void pop(); virtual const T& top() const; virtual bool empty() const; virtual bool full() const; private: class Node { Node(const T& t, Node* n); T data; Node* next; }; Node* p; // pointer naar de top van de stack 40

Stack met lijst (2 van 3) template <typename T> StackWithList<T>::StackWithList(): p(0) { } template <typename T> StackWithList<T>::~StackWithList() { while (!empty()) pop(); template <typename T> bool StackWithList<T>::empty() const { return p == 0; template <typename T> bool StackWithList<T>::full() const { return false; template <typename T> StackWithList<T>::Node::Node(const T& t, Node* n): data(t), next(n) { 41

Stack met lijst (3 van 3) template <typename T> void StackWithList<T>::push(const T& t) { p = new Node(t, p); } template <typename T> void StackWithList<T>::pop() { if (empty()) std::cerr << "Can't pop an empty stack" << endl; else { Node* old = p; p = p->next; delete old; template <typename T> const T& StackWithList<T>::top() const { if (empty()) { std::cerr << "Can't top an empty stack" << std::endl; std::exit(-1); // no valid return return p->data; 42

Array versus gelinkte lijst Array is sneller. Array is statisch. Niet gebruikte gedeelte is overhead. Lijst is dynamisch. Heeft overhead van 1 pointer per element 43

Dynamisch stack kiezen Stack<char>* s = 0; cout << "Welke stack? (l = list, a = array): "; char c; do { cin.get(c); if (c == 'l' || c == 'L') { s = new StackWithList<char>; } else if (c == 'a' || c == 'A') { cout << "Hoeveel elementen?: "; int i; cin >> i; s = new StackWithArray<char>(i); } } while (s == 0); cout << "Type een tekst, sluit af met ." << endl; while (c != '.') { s->push(c); cin.get(c); // ... delete s; 44

Zelfstudie! (Zie studiewijzer) Advanced C++ (namespace, exception, RTTI). Dictaat OGOPRG hoofdstuk 6.2, 6.8 en 6.9. Zie eventueel voor extra informatie: TICPPV1 H10 en TICPPV2 H1 en H8. 45

Algoritmen en Datastructuren ALGODS Week 3

Standaard C++ Library Standaard algoritmen en datastructuren in C++ (voorheen STL = Standard Template Library). Zie http://en.cppreference.com/w/cpp. Zie dictaat hoofdstuk 6. Zie eventueel TICPPV2 hoofdstuk 4 en 5.

STL Containers (datastructuren) Iterators (om door een container te wandelen) Algoritmen (generiek) Het gebruik van iterators maakt generiek programmeren (generic programming) mogelijk. Een generiek algoritme kan op verschillende datatypes (containers) toegepast worden. Generic programming is dus niet OOP. Met behulp van iterators kun je een algoritme op de objecten in een container uitvoeren. De algoritmen zijn zo efficient mogelijk (geen inheritance en virtuele functies gebruikt). Je kunt eigen algoritmen, containers en iteratoren toevoegen.

STL componenten C = container A = algoritme i = iterator Een algoritme kan ook uit één container lezen en in dezelfde container schrijven

Iterator voorbeeld Met behulp van een iterator kun je door een string lopen op dezelfde manier als dat je met een pointer door een char[] kunt lopen. char naam[] = "Henk"; for (const char* p = naam; *p != '\0'; ++p) { cout << *p << " "; } cout << endl; string naam = "Harry"; for (string::const_iterator i = naam.begin(); i != naam.end(); ++i) { cout << *i << " ";

Iterator voorbeeld C++11 Met behulp van een iterator kun je door een string lopen op dezelfde manier als dat je met een pointer door een char[] kunt lopen. char naam[] = "Henk"; for (const auto* p = naam; *p != '\0'; ++p) { cout << *p << " "; } cout << endl; string naam = "Harry"; for (auto i = naam.cbegin(); i != naam.cend(); ++i) { cout << *i << " "; cbegin() geeft een const_iterator terug

Containers Sequentiële containers (linear) [] string array (sinds C++11) vector forward_list (single linked list, sinds C++11) list (double linked list) deque (double ended queue, eigenlijk een devector) bitset (slaan wij over) adapters (in combinatie met vector, list of deque) stack queue priority_queue

Geïmplementeerd met een binairy search tree Containers (vervolg) Associatieve containers (elementen op volgorde van sleutelwaarde opgeslagen) set Verzameling van sleutels (keys). Sleutel moet orgineel zijn. multiset Sleutel kan meerdere malen voorkomen. map Verzameling van paren (sleutel, waarde) (key, value). multimap Geïmplementeerd met een binairy search tree

Containers (vervolg) C++11 Associatieve containers (elementen in willekeurige volgorde opgeslagen) unordered_set Verzameling van sleutels (keys). Sleutel moet orgineel zijn. unordered_multiset Sleutel kan meerdere malen voorkomen. unordered_map Verzameling van paren (sleutel, waarde) (key, value). unordered_multimap Geïmplementeerd met een hash table

Containers De containers regelen hun eigen geheugenbeheer. De containers maken kopietjes van de elementen die erin gestopt worden. Als je dat niet wilt dan moet je een container met pointers gebruiken. Alle objecten in een container zijn van hetzelfde type. (Dat kan wel een polymorf pointertype zijn!)

Sequentiële containers array forward_list vector list deque

Sequentiële containers vector random access op index operator[], at(…) gooit exception out_of_range toevoegen of verwijderen push_back(…) pop_back() O(1) insert(…) erase(…) O(n) deque push_front(…) pop_front() O(1)

Sequentiële containers forward_list geen random access op index toevoegen of verwijderen push_front(…) pop_front() O(1) insert_after(…) erase_after(…) O(1) list push_back(…) pop_back() O(1) insert(…) erase(…) O(1)

Je kunt hier in C++11 ook auto gebruiken! vector voorbeeld #include <iostream> #include <vector> using namespace std; int main() { vector<int> v; void print(const vector<int>& vec); // zelf gedefinieerd int i; cin >> i; while (i != 0) { v.push_back(i); cin >> i; } print(v); if (v.size() >= 4) { for (vector<int>::iterator iter = v.begin() + 2; iter != v.begin() + 4; ++iter) { *iter *= 2; // ... Je kunt hier in C++11 ook auto gebruiken!

Is het niet beter om hier vec.at(index) te gebruiken? vector voorbeeld // print met behulp van een index: void print(const vector<int>& vec) { cout << "De inhoud van de vector is:" << endl; for (vector<int>::size_type index = 0; index != vec.size(); ++index) { cout << vec[index] << " "; } cout << endl; // print met behulp van een iterator: for (auto iter = vec.cbegin(); iter != vec.cend(); ++iter) { cout << *iter << " "; Is het niet beter om hier vec.at(index) te gebruiken? Welke versie is beter?

Kan dat niet eenvoudiger? Generiek voorbeeld // print met behulp van een index: template<typename C> void print(const C& c) { cout << "De inhoud van de container is:" << endl; for (decltype(c.size()) i = 0; i != c.size(); ++i) { cout << c[i] << " "; } cout << endl; // print met behulp van een iterator: for (auto iter = c.cbegin(); iter != c.cend(); ++iter) { cout << *iter << " "; Welke versie is beter? Kan dat niet eenvoudiger?

Hoe kun je een deel van een container printen? Generiek voorbeeld // print met behulp van range based for: template<typename C> void print(const C& c) { cout << "De inhoud van de container is:" << endl; for (const auto& elm: c) { cout << elm << " "; } cout << endl; Welke versie is beter? Hoe kun je een deel van een container printen?

Generiek voorbeeld Welke versie is beter? // print met behulp van twee iteratoren: template <typename Iter> void print(Iter begin, Iter end) { cout << "De inhoud van de container is:" << endl; for (Iter iter = begin; iter != end; ++iter) { cout << *iter << " "; } cout << endl; int main() { vector<int> v; list<double> l; for (int i = 1; i <= 10; ++i) { v.push_back(i); l.push_back(1.0 / i); print(v.cbegin(), v.cend()); // print 1 t/m 10 print(v.cbegin() + 1, v.cend() - 1); // print 2 t/m 9 print(l.cbegin(), l.cend()); Welke versie is beter? 63

list voorbeeld #include <iostream> #include <list> using namespace std; class Hond { public: virtual void blaf() const = 0; // ... }; class Tekkel: public Hond { class SintBernard: public Hond { int main() { list<Hond*> kennel = { new Tekkel, new SintBernard, new Tekkel }; for (const auto hp: kennel) { hp->blaf(); } cin.get(); return 0;

Adapters Container adapters passen de interface van een vector, deque of list aan. stack queue priority_queue stack<int, vector<int>> s1; // stack implemented with vector stack<int, deque<int>> s2; // stack implemented with deque stack<int, list<int>> s3; // stack implemented with list stack<int> s4; // using deque by default Je kunt nu alleen tijdens compile time kiezen welke stack je wilt en niet tijdens run-time. Zie Week 2.

Adapters stack queue priority_queue Kan niet met forward_list (stack gebruikt push_back en pop_back) push(…), pop(), top(), empty() queue kan niet met vector (queue gebruikt push_back en pop_front) Kan niet met forward_list (queue gebruikt push_back en pop_front) push(…), pop(), front(), empty() Let op: push voegt achteraan toe en pop verwijdert vooraan. priority_queue kan niet met list en forward_list (gebruikt index) push(…), pop(), top(), empty() Let op: top geeft het grootste element terug en pop verwijdert dit element. wordt geïmplementeerd als binary heap.

Stacktest #include <iostream> #include <stack> using namespace std; int main() { stack<char> s(32); char c; cout << "Type een tekst, sluit af met ." << endl; cin.get(c); while (c != '.') { s.push(c); } while (!s.empty()) { cout << s.top(); s.pop(); cin.get(); cin.get(); return 0;

Bekende datastructuren 68

Associatieve containers set (verzameling) multiset (bag) map (1:N relatie) multimap (M:N relatie) Mogelijkheden: zoeken op Key doorlopen op volgorde van Key Implementatie: binary search tree Bevat elementen van het type const Key Bevat elementen van het template type pair<const Key, Value>

Associatieve containers unordered_set (verzameling) unordered_multiset (bag) unordered_map (1:N) unordered_multimap (M:N) Mogelijkheden: zoeken op Key Implementatie: hash table Bevat elementen van het type const Key Bevat elementen van het template type pair<const Key, Value>

Associatieve containers

set (verzameling) Toevoegen met insert Verwijderen met erase Een element wordt automatisch op de “goede” plaats ingevoegd. Returntype is een pair<iterator, bool>. De bool geeft aan of het invoegen gelukt is en de iterator geeft de plek aan waar ingevoegd is. Verwijderen met erase Een te verwijderen element wordt automatisch opgezocht. Je kunt ook een iterator meegeven of een range (2 iteratoren). Zoeken met find Geeft een iterator terug naar de plaats waar het element staat en geeft end() terug als element niet gevonden is. Zoeken met count Geeft het aantal keer dat een element voorkomt (0 of 1).

multiset (bag) Toevoegen met insert Verwijderen met erase Een element wordt automatisch op de “goede” plaats ingevoegd. Returntype is een iterator. Deze iterator geeft de plek aan waar ingevoegd is. Verwijderen met erase Een te verwijderen element wordt automatisch opgezocht. Alle gevonden elementen worden verwijderd. Je kunt ook een iterator meegeven of een range (2 iteratoren). Zoeken met find Geeft een iterator terug naar de plaats waar het eerste gevonden element staat en geeft end() terug als element niet gevonden is. Zoeken met count Geeft het aantal keer dat een element voorkomt (0).

set voorbeeld Wat is de uitvoer? #include <iostream> #include <string> #include <set> using namespace std; void print(const set<string>& s) { cout << "De set bevat: "; for (const auto& e: s) { cout << e << " "; } cout << endl; int main() { set<string> docenten = { "Jesse", "Paul", "Ineke", "Harry"}; docenten.insert("Paul"); print(docenten); // ... Wat is de uitvoer? Wat verandert er als we de set vervangen door een unordered_set? Wat verandert er als we de set vervangen door een multiset?

Je kunt hier in C++11 ook auto gebruiken! set voorbeeld #include <iostream> #include <string> #include <set> using namespace std; int main() { set<string> docenten; // … // achteraf testen of insert gelukt is. pair<set<string>::iterator, bool> result = docenten.insert("Harry"); if (!result.second) { cout << "1 Harry is genoeg." << endl; } // vooraf testen of insert mogelijk is. if (docenten.count("Harry")) { Je kunt hier in C++11 ook auto gebruiken!

map (1:N relatie) Elementen zijn: pair<const key, value> interface gelijk aan set insert erase find count extra operator[] met operator[] kun je een key als index gebruiken. Als de key al in de map zit wordt een reference naar de bijbehorende value teruggegeven. Als de key niet aanwezig in de map dan wordt deze key toegevoegd met de default value (default constructor).

multimap (M:N relatie) Elementen zijn: pair<const key, value> interface gelijk aan set insert erase find count geen operator[]

map voorbeeld #include <iostream> #include <fstream> #include <string> #include <map> using namespace std; int main() { string w; map<string, int> freq; // word count cout << "Geef filenaam: "; cin >> w; ifstream fin(w); while (fin >> w) { ++freq[w]; } for (const auto& e: freq) { cout << e.first << " " << e.second << endl;

Algoritmen en Datastructuren ALGODS Week 4

Iterators Een iterator is geen class maar een (interface) afspraak. Elke class die aan deze afspraak voldoet is als iterator te gebruiken. input iterator (single pass) een voor een lezen * (rvalue) ++ output iterator (single pass) een voor een schrijven * (lvalue) ++ forward iterator voorwaarts * ++ == != bidirectional iterator voor-/achterwaarts * ++ -- == != random access iterator met sprongen * ++ -- += -= + - == != > >= < <= [] een gewone pointer is een random access iterator

Iterators

Iterators Relatie met containers Relatie met algoritmes forward iterator forward_list bidirectional iterator list, set, multiset, map en multimap random access iterator vector en deque Relatie met algoritmes input iterator bijvoorbeeld find output iterator bijvoorbeeld copy forward iterator bijvoorbeeld remove bidirectional iterator bijvoorbeeld reverse random access iterator bijvoorbeeld sort

Dit zijn wel echte classes! Speciale iterators Insert-iterators (een soort cursor in insert mode). insert_iterator back_insert_iterator front_insert_iterator Stream-iterators (koppeling tussen iostream library en STL). istream_iterator ostream_iterator Dit zijn wel echte classes!

Speciale iterators voorbeeld vector<int> rij; ifstream fin("getallen.txt"); istream_iterator<int> iin(fin); istream_iterator<int> einde; copy(iin, einde, back_inserter(rij)); sort(rij.begin(), rij.end()); ofstream fout("getallen.txt"); ostream_iterator<int> iout(fout, " "); copy(rij.begin(), rij.end(), iout); Waarom werkt sort(iin, einde) niet?

Generieke algoritmen Een generiek algoritme werkt op een range. Een range wordt aangegeven door twee iteratoren i1 en i2. De range loopt van i1 tot (dus niet t/m) i2. In de wiskunde zouden we dit noteren als [i1, i2). vector<int> v = {12, 18, 6}; sort(v.begin(), v.end()); for (auto e: v) { cout << e << " "; }

Algoritmen vs memberfuncties Een generiek algoritme werkt op meerdere container types. Sommige containers hebben voor bepaalde bewerkingen specifieke memberfuncties. Omdat het generieke algoritme krachtigere iteratoren nodig heeft dan de container kan leveren. Omdat de specifieke memberfunctie sneller is dan het generieke algoritme. Kijk dus voordat je een generiek algoritme gebruikt altijd eerst of er een specifieke memberfunctie is.

Algoritmen vs memberfuncties list<int> l = {12, 18, 6}; sort(l.begin(), l.end()); // O(n log n) l.sort(); // O(n log n) heeft random access iteratoren nodig list levert bidirectionele iteratoren VS2013 error (16 regels) belangrijkste mededeling: binary '-' : 'std::_List_iterator<std::_List_val<std::_List_simple_types<int>>>' does not define this operator or a conversion to a type acceptable to the predefined operator GCC error (58 regels) belangrijkste mededeling: In instantiation of 'void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]': error: no match for 'operator-' in '__last - __first'

Algoritmen vs memberfuncties set<int> s = {12, 6, 18}; auto i1 = find(s.cbegin(), s.cend(), 6); // O(n) if (i1 != s.cend()) { cout << *i1 << " gevonden" << endl; } auto i2 = s.find(6); // O(log n) if (i2 != s.end()) { cout << *i2 << " gevonden" << endl;

Algoritmen Zoeken van elementen Tellen van elementen find zoek element met bepaalde waarde O(n) find_if zoek element met bepaalde eigenschap find_if_not zoek element zonder bepaalde eigenschap (C++11) find_first_of zoek eerste element uit bepaalde range adjacent_find zoek twee opeenvolgende gelijke elementen search_n zoek naar n opeenvolgende gelijke elementen Tellen van elementen count tel elementen met bepaalde waarde count_if tel elementen met bepaalde eigenschap Testen van elementen (C++11) all_of test of alle elementen aan een bepaalde eigenschap voldoen any_of test of een element aan een bepaalde eigenschap voldoet none_of test of geen enkel element aan een bepaalde eigenschap voldoet Inconsequente naamgeving Wat is voordeel t.o.v. count_if?

Inconsequente naamgeving Algoritmen Werken met elementen for_each voer bewerking uit op elk element Zoeken naar een range search zoek naar een range find_end zoek naar een range van achter vandaan Vergelijken van ranges mismatch zoek eerste verschil in twee ranges equal vergelijk twee ranges (returntype is bool) Inconsequente naamgeving

find #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { vector<int> v = {-3, -4, 3, 4}; auto r = find(v.cbegin(), v.cend(), -4); if (r != v.cend()) { cout << "Het eerste element met waarde –4 heeft " << "index: " << r - v.cbegin() << endl; } cin.get(); return 0;

find_if Function ispos is used as predicate #include <iostream> #include <list> #include <algorithm> using namespace std; bool ispos(int i) { return i >= 0; } int main() { list<int> l = {-3, -4, 3, 4}; auto r = find_if(l.cbegin(), l.cend(), ispos); if (r != l.cend()) { cout << "Het eerste positieve element is: " << *r << endl; //... Function ispos is used as predicate Wat als we de eerste waarde >= 1 in de lijst l willen zoeken?

find_if //... class IsPos { public: bool operator()(int i) const { return i >= 0; } }; int main() { list<int> l = {-3, -4, 3, 4}; auto r = find_if(l.cbegin(), l.cend(), IsPos()); if (r != l.cend()) { cout << "Het eerste positieve element is: " << *r << endl; Functor IsPos() is used as predicate Functor is een object dat zich gedraagd als een functie

Functor IsGreaterEqualInt(0) is used as predicate. 0 is nu variabel! find_if //... class IsGreaterEqualInt { public: IsGreaterEqualInt(int r): right(r) {} bool operator()(int left) const { return left >= right; } private: int right; }; int main() { list<int> l = {-3, -4, 3, 4}; auto r = find_if(l.cbegin(), l.cend(), IsGreaterEqualInt(0)); if (r != l.cend()) { cout << "Het eerste positieve element is: " << *r << endl; Functor IsGreaterEqualInt(0) is used as predicate. 0 is nu variabel!

find_if //... template <typename T> class IsGreaterEqual { public: IsGreaterEqual(const T& r): right(r) {} bool operator()(const T& left) const { return left >= right; } private: T right; }; int main() { list<int> l {-3, -4, 3, 4}; auto r = find_if(l.cbegin(), l.cend(), IsGreaterEqual<int>(0)); if (r != l.cend()) { cout << "Het eerste positieve element is: " << *r << endl; Functor IsGreaterEqual<int>(0) is used as predicate. Type int is nu een template parameter (compile time variabel) en 0 is nu variabel!

_1 is a placeholder for the first argument find_if #include <iostream> #include <list> #include <algorithm> #include <functional> using namespace std; using namespace std::placeholders; int main() { list<int> l = {-3, -4, 3, 4}; auto r = find_if(l.cbegin(), l.cend(), bind(greater_equal<int>(), _1, 0)); if (r != l.cend()) { cout << "Het eerste positieve element is: " << *r << endl; } //... Standaard functor bind(greater_equal<int>(), _1, 0) is used as predicate _1 is a placeholder for the first argument

Lambda functie C++11 Een lambda functie is een anonieme functie die eenmalig gebruikt wordt als een functie object (functor). De lambda functie wordt gedefinieerd op de plaats waar het functie object nodig is. Een lambda functie kan dus als predicate gebruikt worden.

find_if Lamda functie [](int i) { return i >= 0; } #include <iostream> #include <list> #include <algorithm> int main() { list<int> l = {-3, -4, 3, 4}; auto r = find_if(l.cbegin(), l.cend(), [](int i) { return i >= 0; }); if (r != l.cend()) { cout << "Het eerste positieve element is: " << *r << endl; } //... Lamda functie [](int i) { return i >= 0; } is used as predicate Voordeel? “eenvoudige” syntax Nadeel? geen hergebruik mogelijk

for_each #include <vector> #include <iostream> #include <iterator> #include <algorithm> using namespace std; void printDubbel(int i) { cout << i << " " << i << " "; } int main() { vector<int> v = {-3, -4, 3, 4}; ostream_iterator<int> iout(cout, " "); copy(v.cbegin(), v.cend(), iout); cout << endl; for_each(v.cbegin(), v.cend(), printDubbel); //...

for_each met lambda #include <vector> #include <iostream> #include <iterator> #include <algorithm> using namespace std; int main() { vector<int> v = {-3, -4, 3, 4}; ostream_iterator<int> iout(cout, " "); copy(v.cbegin(), v.cend(), iout); cout << endl; for_each(v.cbegin(), v.cend(), [](int i) { cout << i << " " << i << " "; }); //...

Alternatief voor for_each #include <vector> #include <iostream> #include <iterator> #include <algorithm> using namespace std; int main() { vector<int> v = {-3, -4, 3, 4}; ostream_iterator<int> iout(cout, " "); copy(v.cbegin(), v.cend(), iout); cout << endl; for (auto i: v) { cout << i << " " << i << " "; }; //... Dit is toch veel simpeler! Wat is dan het nut van for_each? Met for_each kun je ook een deel van een container bewerken!

C++0x closure Een lambda functie kan gebruik maken van identifiers die buiten de lambda functie gedeclareerd zijn. De verzameling van identifiers wordt een closure genoemd. Nederlands: (in)sluiting. Deze closure wordt tussen [ en ] opgegeven. [a, &b] a wordt “by value” en b wordt “by reference” ingesloten. [&] elke gebruikte variabele wordt “by reference” ingesloten. [=] elke gebruikte variabele wordt “by value” ingesloten. [=, &c] c wordt “by reference” ingesloten en alle andere gebruikte variabelen worden “by value” ingesloten.

C++0x closure Bepaal de som van alle even getallen in een vector. int somEven = 0; for_each(v.cbegin(), v.cend(), [&somEven](int i) { if (i % 2 == 0) { somEven += i; } }); [&] werkt ook. Wat is beter?

C++0x lambda return type Een lambda functie kan in veel gevallen zelf zijn return type bepalen. Bij een lambda functie die die dit niet kan moet het return type worden opgegeven. list<double> res = {1.4, 1.5, 4.9, 5.0, 8.9, 9.1, 10.0}; vector<int> geheel; // Alle resultaten < 1.5 moeten worden afgerond tot 1 // Alle resultaten > 9.9 moeten worden afgerond tot 10 // Alle overige resultaten moeten met 0.5 worden verhoogd en // daarna afgerond transform(res.cbegin(), res.cend(), back_inserter(geheel), [](double c) -> int { if (c < 1.5) { return 1; } if (c > 9.9) { return 10; } return round(c + 0.5); }); 1 2 5 6 9 10 10

Algoritmen (vervolg) Vergeten in C++98 toegevoegd in C++11 Kopiëren copy kopieer elementen copy_if kopieer elementen met een bepaalde eigenschap Bewerken transform voer een binaire bewerking uit op twee ranges replace vervang elementen met een bepaalde waarde replace_if vervang elementen met een bepaalde eigenschap replace_copy copy gevolgd door replace replace_copy_if copy gevolgd door replace_if rotate roteer de elementen rotate_copy copy gevolgd door rotate random_shuffle schud de elementen (b.v. kaarten) Verwisselen swap_range verwissel ranges reverse keer de volgorde om reverse_copy copy gevolgd door reverse

transform //... #include <functional> #include <algorithm> using namespace std; int telop(int i, int j) { return i + j; } int main() { vector<int> v = {-3 , -4, 3, 4}, w = {1, 2, 3, 4}; ostream_iterator<int> iout(cout, " "); copy(v.cbegin(), v.cend(), iout); cout << endl; // Bewerking opgeven met een functie. transform(v.cbegin(), v.cend(), w.cbegin(), v.begin(), telop); // Bewerking opgeven met std functie-objecten. transform(v.cbegin(), v.cend(), w.cbegin(), v.begin(), plus<int>());

Algoritmen (vervolg) Verwijderen Diversen remove “verwijder”1 elementen met bepaalde waarde remove_if “verwijder”1 elementen met bepaalde eigenschap remove_copy copy gevolgd door remove remove_copy_if copy gevolgd door remove_if unique “verwijder”1 alle elementen die gelijk zijn aan hun voorganger unique_copy copy gevolgd door unique Diversen fill maak alle elementen gelijk aan bepaalde waarde fill_n fill alleen de eerste n elementen generate maak alle elementen gelijk aan uitvoer van bepaalde functie generate_n generate alleen de eerste n elementen 1 “verwijder” = verwijdert elementen niet echt (geeft iterator terug om te gebruiken in erase)

remove_if //... 0 1 4 9 16 25 36 49 64 81 int main() { 1 9 25 49 81 vector<int> v; for (int i = 0; i < 10; ++i) { v.push_back(i * i); } ostream_iterator<int> out(cout, " "); copy(v.cbegin(), v.cend(), out); cout << endl; vector<int>::iterator end = remove_if(v.begin(), v.end(), bind (not2(modulus<int>()), _1, 2)); copy(v.begin(), end, out); cout << endl; v.erase(end, v.end()); 0 1 4 9 16 25 36 49 64 81 1 9 25 49 81 1 9 25 49 81 25 36 49 64 81

Tip: remove within erase //... int main() { vector<int> v; for (int i = 0; i < 10; ++i) { v.push_back(i * i); } ostream_iterator<int> out(cout, " "); copy(v.cbegin(), v.cend(), out); cout << endl; v.erase(remove_if(v.begin(), v.end(), bind(not2(modulus<int>()), _1, 2)), v.end()); 0 1 4 9 16 25 36 49 64 81 1 9 25 49 81

Algoritmen (vervolg) Sorteren sort sorteer elementen O(n•log n) stable_sort sorteer elementen (gelijke elementen worden niet verwisseld) binary_search zoek in een gesorteerde range O(log n) Set operations (werkt voor alle gesorteerde ranges) includes range1  range 2 set_union  set_intersection  set_difference – set_symmetric_difference  Meer ...

mem_fn #include <iostream> #include <list> #include <algorithm> #include <functional> using namespace std; class Hond { public: virtual void blaf() const = 0; //... }; class Tekkel: public Hond { class StBernard: public Hond { int main() { list<Hond*> k = { new Tekkel, new StBernard, new Tekkel}; for_each( k.cbegin(), k.cend(), mem_fn(&Hond::blaf) ); //...

Alternatief: Lambda functie #include <iostream> #include <list> #include <algorithm> using namespace std; class Hond { public: virtual void blaf() const = 0; //... }; class Tekkel: public Hond { class StBernard: public Hond { int main() { list<Hond*> k = { new Tekkel, new StBernard, new Tekkel}; for_each( k.cbegin(), k.cend(), [](const Hond* hp) { hp->blaf(); } ); //...

Algoritmen en Datastructuren ALGODS Week 5

Games Spel met 2 spelers, die elk afwisselend aan de beurt zijn. Boter Kaas en Eieren (Tic-Tac-Toe). 4 op een rij. Zeeslag Dammen, Schaken, Go, … Hoe vind je de beste zet? Bouw een game tree. Pas het minimax algoritme toe. Gebruik alpha-beta pruning om minimax sneller te maken.

Game tree X X X X O X O X O X Zie Handouts O X O X O X

Backtracking algoritme met minimax strategie! Game tree Zie Handouts Backtracking algoritme met minimax strategie!

Minimax voorbeeld Computer ? Mens ? ? ? ? ? ? ? ? ? ? ? ? ? ? 4 5 3 2 Mens ? ? 1 2 ? ? ? ? 3 4 5 6 ? ? ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

MinMax0.cpp value() //... int value(int pos); int chooseComputerMove(int pos); int chooseHumanMove(int pos); const int UNDECIDED = -1; int value(int pos) { static const int value[16] = {4, 5, 3, 2, 6, 7, 8, 9, 1, 10, 2, 11, 12, 13, 14, 14}; if (pos >= 15 && pos < 31) return value[pos - 15]; // return known value return UNDECIDED; }

MinMax0.cpp chooseComputerMove() //... int chooseComputerMove(int pos) { int bestValue = value(pos); if (bestValue == UNDECIDED) { bestValue = 0; for (int i = 1; i < 3; ++i) { int value = chooseHumanMove(2 * pos + i); if (value > bestValue) { bestValue = value; } return bestValue;

MinMax0.cpp chooseHumanMove() //... int chooseHumanMove(int pos) { int bestValue = value(pos); if (bestValue == UNDECIDED) { bestValue = 15; for (int i = 1; i < 3; ++i) { int value = chooseComputerMove(2 * pos + i); if (value < bestValue) { bestValue = value; } return bestValue;

MinMax0.cpp main() //... int main() { int value = chooseComputerMove(0); cout << "Minimaal te behalen Maximale waarde = " << value << endl; cin.get(); } Minimaal te behalen Maximale waarde = 4

Minimax voorbeeld Computer ? Mens ? ? ? ? ? ? ? ? ? ? ? ? ? ? 4 5 3 2 Mens ? ? 1 2 ? ? ? ? 3 4 5 6 ? ? ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ? Mens ? ? ? ? ? ? ≤4 ? ? ? ? ? ? ? 4 5 3 2 Mens ? ? 1 2 ? ? ? ? 3 4 5 6 ≤4 ? ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ? Mens ? ? ? ? ? ? 4 ? ? ? ? ? ? ? 4 5 3 2 Mens ? ? 1 2 ? ? ? ? 3 4 5 6 4 ? ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ? Mens ? ? ≥4 ? ? ? 4 ? ? ? ? ? ? ? 4 5 3 2 Mens ? ? 1 2 ≥4 ? ? ? 3 4 5 6 4 ? ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ? Mens ? ? ≥4 ? ? ? 4 ≤3 ? ? ? ? ? ? 4 5 3 Mens ? ? 1 2 ≥4 ? ? ? 3 4 5 6 4 ≤3 ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ? Mens ? ? ≥4 ? ? ? 4 2 ? ? ? ? ? ? 4 5 3 2 Mens ? ? 1 2 ≥4 ? ? ? 3 4 5 6 4 2 ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ? Mens ? ? 4 ? ? ? 4 2 ? ? ? ? ? ? 4 5 3 2 Mens ? ? 1 2 4 ? ? ? 3 4 5 6 4 2 ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ? Mens ≤4 ? 4 ? ? ? 4 2 ? ? ? ? ? ? 4 5 3 2 Mens ≤4 ? 1 2 4 ? ? ? 3 4 5 6 4 2 ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ? Mens ≤4 ? 4 ? ? ? 4 2 ≤6 ? ? ? ? ? 4 5 3 Mens ≤4 ? 1 2 4 ? ? ? 3 4 5 6 4 2 ≤6 ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ? Mens ≤4 ? 4 ? ? ? 4 2 6 ? ? ? ? ? 4 5 3 2 Mens ≤4 ? 1 2 4 ? ? ? 3 4 5 6 4 2 6 ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ? Mens ≤4 ? 4 ≥6 ? ? 4 2 6 ? ? ? ? ? 4 5 3 Mens ≤4 ? 1 2 4 ≥6 ? ? 3 4 5 6 4 2 6 ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ? Mens ≤4 ? 4 ≥6 ? ? 4 2 6 ≤8 ? ? ? ? 4 5 3 Mens ≤4 ? 1 2 4 ≥6 ? ? 3 4 5 6 4 2 6 ≤8 ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ? Mens ≤4 ? 4 ≥6 ? ? 4 2 6 8 ? ? ? ? 4 5 3 Mens ≤4 ? 1 2 4 ≥6 ? ? 3 4 5 6 4 2 6 8 ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ? Mens ≤4 ? 4 8 ? ? 4 2 6 8 ? ? ? ? 4 5 3 2 Mens ≤4 ? 1 2 4 8 ? ? 3 4 5 6 4 2 6 8 ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ? Mens 4 ? 4 6 ? ? 4 2 6 8 ? ? ? ? 4 5 3 2 Mens 4 ? 1 2 4 6 ? ? 3 4 5 6 4 2 6 8 ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ≥4 Mens 4 ? 4 6 ? ? 4 2 6 8 ? ? ? ? 4 5 3 2 Mens 4 ? 1 2 4 6 ? ? 3 4 5 6 4 2 6 8 ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ≥4 Mens 4 ? 4 6 ? ? 4 2 6 8 ≤1 ? ? ? 4 5 3 Mens 4 ? 1 2 4 6 ? ? 3 4 5 6 4 2 6 8 ≤1 ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ≥4 Mens 4 ? 4 8 ? ? 4 2 6 8 1 ? ? ? 4 5 3 2 Mens 4 ? 1 2 4 8 ? ? 3 4 5 6 4 2 6 8 1 ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ≥4 Mens 4 ? 4 8 ≥1 ? 4 2 6 8 1 ? ? ? 4 5 3 Mens 4 ? 1 2 4 8 ≥1 ? 3 4 5 6 4 2 6 8 1 ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ≥4 Mens 4 ? 4 8 ≥1 ? 4 2 6 8 1 ≤2 ? ? 4 5 3 Mens 4 ? 1 2 4 8 ≥1 ? 3 4 5 6 4 2 6 8 1 ≤2 ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ≥4 Mens 4 ? 4 8 ≥1 ? 4 2 6 8 1 2 ? ? 4 5 3 Mens 4 ? 1 2 4 8 ≥1 ? 3 4 5 6 4 2 6 8 1 2 ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ≥4 Mens 4 ? 4 8 2 ? 4 2 6 8 1 2 ? ? 4 5 3 2 Mens 4 ? 1 2 4 8 2 ? 3 4 5 6 4 2 6 8 1 2 ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ≥4 Mens 4 ≤2 4 8 2 ? 4 2 6 8 1 2 ? ? 4 5 3 Mens 4 ≤2 1 2 4 8 2 ? 3 4 5 6 4 2 6 8 1 2 ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ≥4 Mens 4 ≤2 4 8 2 ? 4 2 6 8 1 2 ≤12 ? 4 5 Mens 4 ≤2 1 2 4 8 2 ? 3 4 5 6 4 2 6 8 1 2 ≤12 ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ≥4 Mens 4 ≤2 4 8 2 ? 4 2 6 8 1 2 12 ? 4 5 3 Mens 4 ≤2 1 2 4 8 2 ? 3 4 5 6 4 2 6 8 1 2 12 ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ≥4 Mens 4 ≤2 4 8 2 ≥12 4 2 6 8 1 2 12 ? 4 5 Mens 4 ≤2 1 2 4 8 2 ≥12 3 4 5 6 4 2 6 8 1 2 12 ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ≥4 Mens 4 ≤2 4 8 2 ≥12 4 2 6 8 1 2 12 ≤14 4 Mens 4 ≤2 1 2 4 8 2 ≥12 3 4 5 6 4 2 6 8 1 2 12 ≤14 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ≥4 Mens 4 ≤2 4 8 2 ≥12 4 2 6 8 1 2 12 14 4 Mens 4 ≤2 1 2 4 8 2 ≥12 3 4 5 6 4 2 6 8 1 2 12 14 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ≥4 Mens 4 ≤2 4 8 2 14 4 2 6 8 1 2 12 14 4 5 Mens 4 ≤2 1 2 4 8 2 14 3 4 5 6 4 2 6 8 1 2 12 14 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer ≥4 Mens 4 2 4 8 2 14 4 2 6 8 1 2 12 14 4 5 Mens 4 2 1 2 4 8 2 14 3 4 5 6 4 2 6 8 1 2 12 14 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer 4 Mens 4 2 4 8 2 14 4 2 6 8 1 2 12 14 4 5 3 Mens 4 2 1 2 4 8 2 14 3 4 5 6 4 2 6 8 1 2 12 14 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minimax voorbeeld Computer 4 Mens 4 2 4 8 2 14 4 2 6 8 1 2 12 14 4 5 3 Mens 4 2 1 2 4 8 2 14 3 4 5 6 4 2 6 8 1 2 12 14 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Minmax voorbeeld Niet alleen de beste waarde maar ook de beste keuze moet worden bepaald!

Minimax voorbeeld Computer 4 Mens 4 2 4 8 2 14 4 2 6 8 1 2 12 14 4 5 3 Mens 4 2 1 2 4 8 2 14 3 4 5 6 4 2 6 8 1 2 12 14 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

MinMax2.cpp chooseComputerMove() //... int chooseComputerMove(int pos, int& bestNextPos) { int bestValue = value(pos); if (bestValue == UNDECIDED) { bestValue = 0; for (int i = 1; i < 3; ++i) { int dummyPos; int value = chooseHumanMove(2 * pos + i, dummyPos); if (value > bestValue) { bestValue = value; bestNextPos = 2 * pos + i; } return bestValue;

MinMax2.cpp chooseHumanMove() //... int chooseHumanMove(int pos, int& bestNextPos) { int bestValue = value(pos); if (bestValue == UNDECIDED) { bestValue = 15; for (int i = 1; i < 3; ++i) { int dummyPos; int value = chooseComputerMove(2 * pos + i, dummyPos); if (value < bestValue) { bestValue = value; bestNextPos = 2 * pos + i; } return bestValue;

MinMax2.cpp main() int main() { int pos = 0, bestNextPos, bestValue; while (pos < 15) { bestValue = chooseComputerMove(pos, bestNextPos); cout << "Minimaal te behalen Maximale waarde = " << bestValue << endl; pos = bestNextPos; cout << "Computer kiest positie: " << pos << endl; int posL = 2 * pos + 1, posR = 2 * pos + 2; if (pos < 15) { cout << "Je kunt kiezen voor positie " << posL << " of positie " << posR << endl; chooseHumanMove(pos, bestNextPos); cout << "Pssst, " << bestNextPos << " is de beste keuze." << endl; do { cout << "Maak je keuze: "; cin >> pos; } while (pos != posL && pos != posR); } cout << "Behaalde waarde = " << value(pos) << endl; //...

MinMax2.cpp main() Minimaal te behalen Maximale waarde = 4 Computer kiest positie: 1 Je kunt kiezen voor positie 3 of positie 4 Pssst, 3 is de beste keuze. Maak je keuze: 4 Minimaal te behalen Maximale waarde = 8 Computer kiest positie: 10 Je kunt kiezen voor positie 21 of positie 22 Pssst, 21 is de beste keuze. Maak je keuze: 22 Behaalde waarde = 9

Minimax voorbeeld Computer 4 Mens 4 2 4 8 2 14 4 2 6 8 1 2 12 14 4 5 3 Mens 4 2 1 2 4 8 2 14 3 4 5 6 4 2 6 8 1 2 12 14 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ? Mens ? ? 1 2 ? ? ? ? 3 4 5 6 ? ? ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ? Mens ? ? 1 2 ? ? ? ? 3 4 5 6 ≤4 ? ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ? Mens ? ? 1 2 ? ? ? ? 3 4 5 6 4 ? ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ? Mens ? ? 1 2 ≥4 ? ? ? 3 4 5 6 4 ? ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ? Mens ? ? 1 2 ≥4 ? ? ? 3 4 5 6 4 ≤3 ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 2 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ? Mens ? ? 1 2 ≥4 ? ? ? 3 4 5 6 4 ≤3 ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 19 20 21 22 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ? Mens ? ? 1 2 4 ? ? ? 3 4 5 6 4 ≤3 ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 19 20 21 22 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ? Mens ≤4 ? 1 2 4 ? ? ? 3 4 5 6 4 ≤3 ? ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 19 20 21 22 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ? Mens ≤4 ? 1 2 4 ? ? ? 3 4 5 6 4 ≤3 ≤6 ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 19 20 21 22 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ? Mens ≤4 ? 1 2 4 ? ? ? 3 4 5 6 4 ≤3 6 ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 19 20 21 22 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ? Mens ≤4 ? 1 2 4 ≥6 ? ? 3 4 5 6 4 ≤3 6 ? ? ? ? ? 7 8 9 10 11 12 13 14 4 5 3 6 7 8 9 1 10 2 11 12 13 14 14 15 16 17 19 20 21 22 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ? Mens ≤4 ? 1 2 4 ≥6 ? ? 3 4 5 6 4 ≤3 6 ? ? ? ? 7 8 9 11 12 13 14 4 5 3 6 7 1 10 2 11 12 13 14 14 15 16 17 19 20 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ? Mens 4 ? 1 2 4 ≥6 ? ? 3 4 5 6 4 ≤3 6 ? ? ? ? 7 8 9 11 12 13 14 4 5 3 6 7 1 10 2 11 12 13 14 14 15 16 17 19 20 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ≥4 Mens 4 ? 1 2 4 ≥6 ? ? 3 4 5 6 4 ≤3 6 ? ? ? ? 7 8 9 11 12 13 14 4 5 3 6 7 1 10 2 11 12 13 14 14 15 16 17 19 20 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ≥4 Mens 4 ? 1 2 4 ≥6 ≥4 ? 3 4 5 6 4 ≤3 6 ? ? ? ? 7 8 9 11 12 13 14 4 5 3 6 7 1 10 2 11 12 13 14 14 15 16 17 19 20 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ≥4 Mens 4 ? 1 2 4 ≥6 ≥4 ? 3 4 5 6 4 ≤3 6 ≤1 ? ? ? 7 8 9 11 12 13 14 4 5 3 6 7 1 10 2 11 12 13 14 14 15 16 17 19 20 23 24 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ≥4 Mens 4 ? 1 2 4 ≥6 ≤1 ≥4 ? 3 4 5 6 4 ≤3 6 ? ? ? 7 8 9 11 12 13 14 4 5 3 6 7 1 2 11 12 13 14 14 15 16 17 19 20 23 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ≥4 Mens 4 ? 1 2 4 ≥6 ≤1 ≥4 ? 3 4 5 6 4 ≤3 6 ? ? ? 7 8 9 11 12 13 14 4 5 3 6 7 1 2 11 12 13 14 14 15 16 17 19 20 23 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ≥4 Mens 4 ? 1 2 4 ≥6 ≤1 ≥4 ? 3 4 5 6 4 ≤3 6 ≤2 ? ? 7 8 9 11 12 13 14 4 5 3 6 7 1 2 11 12 13 14 14 15 16 17 19 20 23 25 26 27 28 29 30

Alpha-beta pruning voorbeeld Computer ≥4 Mens 4 ? 1 2 4 ≥6 ≤1 ≥4 ? 3 4 5 6 4 ≤3 6 ≤2 ? ? 7 8 9 11 12 13 14 4 5 3 6 7 1 2 12 13 14 14 15 16 17 19 20 23 25 27 28 29 30

Alpha-beta pruning voorbeeld Computer ≥4 Mens 4 ? 1 2 4 ≥6 ≤1 ≥4 ? 3 4 5 6 4 ≤3 6 ≤2 ? ? 7 8 9 11 12 13 14 4 5 3 6 7 1 2 12 13 14 14 15 16 17 19 20 23 25 27 28 29 30

Alpha-beta pruning voorbeeld Computer ≥4 Mens 4 ≤4 1 2 4 ≥6 ≥4 ? 3 4 5 6 4 ≤3 6 ≤1 ≤2 ? ? 7 8 9 11 12 13 14 4 5 3 6 7 1 2 12 13 14 14 15 16 17 19 20 23 25 27 28 29 30

Alpha-beta pruning voorbeeld Computer ≥4 Mens 4 ≤4 1 2 4 ≥6 ≥4 3 4 5 4 ≤3 6 ≤1 ≤2 7 8 9 11 12 4 5 3 6 7 1 2 15 16 17 19 20 23 25

Alpha-beta pruning voorbeeld Computer 4 Mens 4 ≤4 1 2 4 ≥6 ≥4 3 4 5 4 ≤3 6 ≤1 ≤2 7 8 9 11 12 4 5 3 6 7 1 2 15 16 17 19 20 23 25

Alpha-beta pruning voorbeeld Computer 4 Mens 4 ≤4 1 2 4 ≥6 ≥4 3 4 5 4 ≤3 6 ≤1 ≤2 7 8 9 11 12 4 5 3 6 7 1 2 15 16 17 19 20 23 25

AlphaBeta2.cpp chooseComputerMove() //... int chooseComputerMove(int pos, int& bestNextPos, int alpha, int beta) { int bestValue = value(pos); if (bestValue == UNDECIDED) { bestValue = alpha; for (int i = 1; bestValue < beta && i < 3; ++i) { int dummyPos; int value = chooseHumanMove(2 * pos + i, dummyPos, alpha, beta); if (value > bestValue) { bestValue = value; alpha = bestValue; bestNextPos = 2 * pos + i; } return bestValue;

AlphaBeta2.cpp chooseComputerMove() //... int chooseComputerMove(int pos, int& bestNextPos, int alpha, int beta) { int bestValue = value(pos); if (bestValue == UNDECIDED) { bestValue = alpha; for (int i = 1; alpha < beta && i < 3; ++i) { int dummyPos; int value = chooseHumanMove(2 * pos + i, dummyPos, alpha, beta); if (value > bestValue) { bestValue = value; alpha = bestValue; bestNextPos = 2 * pos + i; } return bestValue; Maakt niet uit voor de werking!

AlphaBeta2.cpp chooseHumanMove() //... int chooseHumanMove(int pos, int& bestNextPos, int alpha, int beta) { int bestValue = value(pos); if (bestValue == UNDECIDED) { bestValue = beta; for (int i = 1; bestValue > alpha && i < 3; ++i) { int dummyPos; int value = chooseComputerMove(2 * pos + i, dummyPos, alpha, beta); if (value < bestValue) { bestValue = value; beta = bestValue; bestNextPos = 2 * pos + i; } return bestValue;

AlphaBeta2.cpp chooseHumanMove() //... int chooseHumanMove(int pos, int& bestNextPos, int alpha, int beta) { int bestValue = value(pos); if (bestValue == UNDECIDED) { bestValue = beta; for (int i = 1; beta > alpha && i < 3; ++i) { int dummyPos; int value = chooseComputerMove(2 * pos + i, dummyPos, alpha, beta); if (value < bestValue) { bestValue = value; beta = bestValue; bestNextPos = 2 * pos + i; } return bestValue; Maakt niet uit voor de werking!

AlphaBeta2.cpp chooseHumanMove() //... int chooseHumanMove(int pos, int& bestNextPos, int alpha, int beta) { int bestValue = value(pos); if (bestValue == UNDECIDED) { bestValue = beta; for (int i = 1; alpha < beta && i < 3; ++i) { int dummyPos; int value = chooseComputerMove(2 * pos + i, dummyPos, alpha, beta); if (value < bestValue) { bestValue = value; beta = bestValue; bestNextPos = 2 * pos + i; } return bestValue; Maakt niet uit voor de werking! Voorwaarde voor snoeien is: alpha ≥ beta Bijhouden bestValue is niet nodig.

AlphaBeta2.cpp chooseComputerMove() //... int chooseComputerMove(int pos, int& bestNextPos, int alpha, int beta) { int bestValue = value(pos); if (bestValue == UNDECIDED) { for (int i = 1; alpha < beta && i < 3; ++i) { int dummyPos; int value = chooseHumanMove(2 * pos + i, dummyPos, alpha, beta); if (value > alpha) { alpha = value; bestNextPos = 2 * pos + i; } bestValue = alpha; return bestValue;

AlphaBeta2.cpp chooseHumanMove() //... int chooseHumanMove(int pos, int& bestNextPos, int alpha, int beta) { int bestValue = value(pos); if (bestValue == UNDECIDED) { for (int i = 1; alpha < beta && i < 3; ++i) { int dummyPos; int value = chooseComputerMove(2 * pos + i, dummyPos, alpha, beta); if (value < beta) { beta = value; bestNextPos = 2 * pos + i; } bestValue = beta; return bestValue;

Alpha-beta pruning voorbeeld Computer alpha,beta 4 Mens 0,15 4,15 4 4 4,4 1 2 0,15 0,4 4,15 4 4 4 3 4 4,4 5 0,15 4,15 0,4 4,15 4,15 4 3 4 1 2 7 8 9 11 12 4,3 4,1 4,2 0,15 0,4 4,15 0,4 0,4 4,15 4,15 4 5 3 6 7 1 2 15 16 17 19 20 23 25

AlphaBeta1Verbose.cpp Code: zie dictaat. snoei node 18 snoei node 10 Minimaal te behalen Maximale waarde = 4

TicTacToe class TicTacToe { public: enum Side {EMPTY, HUMAN, COMPUTER}; enum Value {HUMAN_WINS = -1, DRAW, COMPUTER_WINS, UNDECIDED}; TicTacToe() { fill(board.begin(), board.end(), EMPTY); } Value chooseComputerMove(int& bestRow, int& bestColumn); Value chooseHumanMove(int& bestRow, int& bestColumn); Side side(int row, int column) const; bool isUndecided() const; bool playMove(Side s, int row, int column); bool boardIsFull() const; bool isAWin(Side s) const; private: typedef matrix<Side, 3, 3> Board; Board board; Value value() const; };

TicTacToe::chooseComputerMove TicTacToe::Value TicTacToe::chooseComputerMove(int& bestRow, int& bestColumn) { Value bestValue = value(); if (bestValue == UNDECIDED) { bestValue = HUMAN_WINS; for (int row = 0; row < 3; ++row) { for (int column = 0; column < 3; ++column) { if (board(row, column) == EMPTY) { board(row, column) = COMPUTER; int dummyRow, dummyColumn; Value value = chooseHumanMove(dummyRow, dummyColumn); board(row, column) = EMPTY; if (value > bestValue) { bestValue = value; bestRow = row; bestColumn = column; } return bestValue;

TicTacToe::chooseHumanMove TicTacToe::Value TicTacToe::chooseHumanMove(int& bestRow, int& bestColumn) { Value bestValue = value(); if (bestValue == UNDECIDED) { bestValue = COMPUTER_WINS; for (int row = 0; row < 3; ++row) { for (int column = 0; column < 3; ++column) { if (board(row, column) == EMPTY) { board(row, column) = HUMAN; int dummyRow, dummyColumn; Value value = chooseComputerMove(dummyRow, dummyColumn); board(row, column) = EMPTY; if (value < bestValue) { bestValue = value; bestRow = row; bestColumn = column; } return bestValue;

Tic-Tac-Toe aantal aanroepen chooseComputerMove bij eerste zet (computer begint): Maximaal: 1+9+9x8+9x8x7+ ... + 9x8x7x6x5x4x3x2x1 = 986410 Stoppen als er een winnaar is = 549946 Toepassen alpha-beta pruning = 16811 Toepassen (maximale) transposition table = 4272

Tic-Tac-Toe aantal aanroepen en execution time chooseComputerMove bij eerste en derde zet (computer begint): Zet 1 Zet 3 Time Moves TicTacSlow.cpp 2,202610 549946 0,034667 8232 TicTacAB.cpp 0,071300 16811 0,002244 450 TicTacMap.cpp 0,183925 4272 0,000028 1

Transpostions Door zetverwisselig bereik je soms dezelfde positie. Idee: sla berekende posities op en zoek voordat je rekent.

BoardWrapper is een wrapper (inpakker) voor Board. TicTacMap.cpp class TicTacToe { //... private: class BoardWrapper { public: BoardWrapper(const Board& b); bool operator<(const BoardWrapper& rhs) const; Board board; }; class ValueAndBestMove { ValueAndBestMove() = default; ValueAndBestMove(Value v, int r, int c); Value value; int bestRow, bestColumn; map<BoardWrapper, ValueAndBestMove> boards; BoardWrapper is een wrapper (inpakker) voor Board. Waarom is dit nodig?

TicTacMap.cpp bool TicTacToe::BoardWrapper::operator<(const BoardWrapper& rhs) const { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (board(i, j) != rhs.board(i, j)) { return board(i, j) < rhs.board(i, j); } return false; Voldoet deze implementatie aan de regels die moeten gelden voor een < operatie? a < a  false a < b  !(b < a) a < b && b < c  a < c

TicTacMap.cpp TicTacToe::Value TicTacToe::chooseComputerMove(int& bestRow, int& bestColumn, Value alpha, Value beta) { auto itr = boards.find(BoardWrapper(board)); if (itr != boards.end()) { bestRow = itr->second.bestRow; bestColumn = itr->second.bestColumn; return itr->second.value; } Value bestValue = value(); if (bestValue == UNDECIDED) { for (int row = 0; alpha < beta && row < 3; ++row) { //... bestValue = alpha; boards[BoardWrapper(board)] = ValueAndBestMove(bestValue, bestRow, bestColumn); return bestValue;

TicTacMapRestrictedDepth.cpp Verklaar? TicTacToe::Value TicTacToe::chooseComputerMove(int& bestRow, int& bestColumn, Value alpha, Value beta, int depth) { if (depth >= 3 && depth <= MAX_DEPTH) { auto itr = boards.find(BoardWrapper(board)); if (itr != boards.end()) { bestRow = itr->second.bestRow; bestColumn = itr->second.bestColumn; return itr->second.value; } //... Value value = chooseHumanMove(dummyRow, dummyColumn, alpha, beta, depth + 1); boards[BoardWrapper(board)] = ValueAndBestMove( bestValue, bestRow, bestColumn); return bestValue; Verklaar?

TicTacDetermineMaxTableDepth.cpp Debug mode

TicTacDetermineMaxTableDepth.cpp Release mode

Alternatief voor map Volgorde van stellingen is niet belangrijk. Gebruik van unordered_map ligt dus meer voor de hand. Ook een perfect hash met behulp van een array is mogelijk (en véél sneller). Idee van Remco Boom.

Ingewikkelder spel Doorrekenen van de hele boom duurt te lang: reken tot een bepaalde diepte en “schat” daar de waarde van de stelling. Dilemma: schatten kost veel tijd  geen tijd om diep te rekenen. schatten kost minder tijd  tijd om dieper te rekenen. Transpositiematrix weggooien na berekenen van een computerzet. Waarom? Algoritme kan verliezen: algoritme zoals tot nu besproken bevat een BUG! Kan niet tegen zijn verlies ;-) (gevonden en hersteld door Marc Cornet)

TicTacABLoser.cpp // place computer in losing situation t.playMove(TicTacToe::HUMAN, 0, 0); t.playMove(TicTacToe::COMPUTER, 0, 1); t.playMove(TicTacToe::HUMAN, 1, 1); printBoard(); doComputerMove(); --- xo x Calculation time: 0.00114894 sec Moves considered: 238 Computer plays: ROW = -858993460 COLUMN = -858993460

TicTacABLoser.cpp Oplossing: Initialiseer bestRow en bestColumn met een geldige zet voordat chooseComputerMove wordt aangeroepen Als de waarde van een stelling gelijk is aan de huidige beste waarde kies dan die stelling Beide oplossingen zijn niet ideaal omdat computer geen tegenspel meer geeft maar “opgeeft” zodra hij verloren staat.

TicTacABLoser.cpp --- xo x Calculation time: 0.00518334 sec Moves considered: 238 Computer plays: ROW = 0 COLUMN = 2 xoo

Algoritmen en Datastructuren ALGODS Week 6

Bekende datastructuren 213

Grafen: definities Graph bestaat uit Edge verbind twee vertices. 4 5 1 17 11 6 Graph bestaat uit verzameling vertices [vur-tuh-seez] (nodes) en verzameling edges (arcs). Edge verbind twee vertices. In een directed graph (digraph) hebben de edges een richting. Vertex v is adjacent to w als er een edge is van v naar w. Edge heeft mogelijk cost (of weight).

Grafen: definities Path is een rijtje vertices verbonden door edges. 6 4 11 V2 V3 17 Path is een rijtje vertices verbonden door edges. Path length = aantal edges in path. Weighted path length = som van de costs van de edges in path. Cycle = path van vertix naar zichzelf met lengte > 0. DAG = directed acyclic graph = directed graph zonder cycles. 1 V4 5 V5

Grafen: toepassingen Computernetwerk (Internet) Openbaar vervoer Telefoonnetwerk Voor de meeste praktische toepassingen geldt dat het aantal edges veel kleiner is dan alle mogelijke verbindingen = sparce graph. Belangrijk algoritme: bepalen shortest path.

Grafen: datastructuur Matrix |V| x |V| Elk element m[v][w] bevat de cost van de edge van v naar w. Cost = oneindig als edge niet bestaat. Benodigde geheugen O(|V|2). Niet geschikt voor sparce graphs. Adjacency list Maak voor elke vertex een lijstje met uitgaande edges (adjacent vertice met de bijbehorende costs). struct Edge { Vertex* destination; int costs; }; Elke Vertex bevat een list<Edge> adjacent. Benodigde geheugen O(|E|).

Grafen: datastructuren class Graph { public: // ... private: struct Vertex { // Vertex kan alleen gebruikt worden door // memberfuncties van Graph Vertex(const string& name); string name; struct Edge { // Edge kan alleen gebruikt worden door Vertex* destination; int costs; }; list<Edge> adjacent; map<string, Vertex*> vertexes; // vertex op naam opgeslagen static const int INF = INT_MAX;

Vertex struct Vertex { Vertex(const string& name); void addEdge(Vertex* v, int costs); string name; struct Edge { Edge(Vertex* v, int costs); Vertex* destination; int costs; }; list<Edge> adjacent; // used for shortest-path algorithms void reset(); void printPath() const; Vertex* previous; bool isProcessed; // used for dijkstra algorithm unsigned int timesQueued; // used for negative algorithm bool isOnQueue; // used for negative algorithm unsigned int indegree; // used for acyclic algorithm

Vertex Graph::Vertex::Edge::Edge(Vertex* v, int costs): destination(v), costs(costs) { } Graph::Vertex::Vertex(const string& name): name(name) { reset(); void Graph::Vertex::addEdge(Vertex* v, int costs) { adjacent.push_back(Graph::Vertex::Edge(v, costs)); void Graph::Vertex::reset() { costs = INF; previous = 0; isProcessed = isOnQueue = false; timesQueued = indegree = 0; void Graph::Vertex::printPath() const { if (previous) { previous->printPath(); cout << " to "; cout << name;

Graph class Graph { public: ~Graph(); void addEdge(const string& sourceName, const string& destName, int cost); void printPath(const string& destName) const; void unweighted(const string& startName); void dijkstra(const string& startName); void negative(const string& startName); void acyclic(const string& startName); private: struct Vertex { /* … */ }; // getVertex creates a Vertex when it does not exists Vertex* getVertex(const string& vertexName); // find Vertex throws an exception when the Vertex does not exists Vertex* findVertex(const string& vertexName); const Vertex* findVertex(const string& vertexName) const; void reset();

Graph Graph::~Graph() { for (auto& p : vertices) { delete p.second; } void Graph::reset() { for (auto& p : vertices) { p.second->reset(); } Graph::Vertex* Graph::getVertex(const string& vertexName) { Vertex* v = vertices[vertexName]; if (v == 0) { v = new Vertex(vertexName); vertices[vertexName] = v; return v; Graph::Vertex* Graph::findVertex(const string& vertexName) { auto itr = vertices.find(vertexName); if (itr == vertices.end()) throw runtime_error(vertexName + " not found"); return itr->second;

Graph void Graph::addEdge(const string& sourceName, const string& destName, int cost) { Vertex* v = getVertex(sourceName); Vertex* w = getVertex(destName); v->addEdge(w, cost); } void Graph::printPath(const string& destinationName) const { const Vertex* destination = findVertex(destinationName); if (destination->costs == INF) cout << destinationName << " is unreachable"; else { cout << "(Costs are: " << destination->costs << ") "; destination->printPath(); cout << endl;

Unweighted shortest path Voor elke vertex: costs = INF Voor start vertex: costs = 0 Voor alle vertices met costs == 0: Voor alle adjacent vertices: if costs == INF costs = 1 Voor alle vertices met costs == 1: if costs == INF costs = 2 Enz... Single source algoritme Uitgaande van een start vertex wordt het kortste pad naar alle andere vertices berekend. (Geldt voor alle SP algoritmen)

USP (Breadth-first search) V0 V1 V3 V4 V2 V6 V5

USP (Breadth-first search) costs ∞ 1 costs ∞ 2 V0 V1 costs V3 V4 costs ∞ 3 ∞ V2 costs ∞ 2 V6 V5 costs ∞ costs ∞ 1 3

Unweighted shortest path Eerste keer dat costs een waarde != INF krijgt is dit meteen de kortste afstand. Je kunt dan meteen de previous pointer goed zetten. Volgorde van de te bezoeken vertices kan als volgt bepaald worden: Zet start vertex in een queue. Zolang queue niet leeg: Haal vertex v uit queue. Voor alle adjacent vertices w: Als costsw == INF. costsw = costsv + 1. Zet vertex w in de queue.

Unweighted shortest path void Graph::unweighted(const string& startName){ reset(); Vertex* start = findVertex(startName); start->costs = 0; queue<Vertex*> q; q.push(start); while (!q.empty()) { Vertex* v = q.front(); q.pop(); for (auto& e : v->adjacent) { Vertex* w = e.destination; if (w->costs == INF) { w->costs = v->costs + 1; w->previous = v; q.push(w); }

USP O(|E|) Orde USP Elke Vertex wordt 1x in de queue gezet en dus ook 1x uit de queue gehaald. Inzetten en uithalen is O(1). Elke Vertex wordt dus 1x bezocht . Bij een bezoek worden alle adjacent Edges bekeken. Voor het hele algoritme geldt dus dat elke Edge 1x wordt bekeken O(|E|)

Positive-weighted shortest path Dijkstra’s algoritme Als vertex w adjacent to vertex v is: costsw = costsv + costsv,w als deze waarde kleiner is dan de huidige waarde van costsw Het is nu niet meer mogelijk om de costs van elke vertex maar 1x aan te passen.

Positive-weighted shortest path Volgorde van de te bezoeken vertices kan als volgt bepaald worden: Zet start vertex in een priority_queue die laagste costs vooraan zet. Zolang priority_queue niet leeg: Haal vertex v uit priority_queue. Voor alle adjacent vertices w: Als costsw > costsv + costsv,w costsw = costsv + costsv,w Zet vertex w in de priority_queue.

Positive-weighted shortest path void Graph::dijkstra(const string& startName) { reset(); Vertex* start = findVertex(startName); start->costs = 0; auto ptrVectorGreater = [](Vertex* p, Vertex* q) { return p->costs > q->costs; }; priority_queue<Vertex*, vector<Vertex*>, decltype(ptrVectorGreater)> pq(ptrVectorGreater); pq.push(start); // see next page

Positive-weighted shortest path while (!pq.empty()) { Vertex* v = pq.top(); pq.pop(); for (auto& e: v->adjacent) { Vertex* w = e.destination; int cvw = e.costs; if (cvw < 0) { throw runtime_error("Graph has negative edges"); } if (w->costs > v->costs + cvw) { w->costs = v->costs + cvw; w->previous = v; pq.push(w);

Dijkstra’s algoritme 2 V0 V1 6 10 4 3 2 V3 2 V4 V2 4 8 5 6 V6 V5 1

Dijkstra’s algoritme previous costs ∞ costs ∞ 2 V0 V1 6 10 4 3 costs 2 costs ∞ 2 2 V0 V1 6 10 4 3 costs 2 V3 2 V4 costs ∞ 12 7 ∞ 7 V2 4 8 costs 5 6 ∞ 6 5 V6 V5 1 costs ∞ 12 10 costs ∞ 13 9

Dijkstra’s algoritme Optimalisatie: Een Vertex* kan meerdere keren in de priority_queue worden geplaatst (steeds met lagere costs). Een vertex hoeft maar 1x te worden “afgehandeld”. De eerste keer dat een Vertex* uit de priority_queue wordt gehaald worden alle adjacent vertices onderzocht. De variabele isProcessed wordt gebruikt om aan te geven of de vertex al is afgehandeld (isProcessed == true). maak isProcessed true als Vertex* (voor het eerst) uit de priority_queue wordt gehaald. Als isProcessed == true als Vertex* uit de priority_queue wordt gehaald, hoef je niets meer te doen. Vraag: Waarom moet Vertex opnieuw in de priority_queue worden geplaatst als de costs aangepast (verlaagd) zijn?

Optimalisatie while (!pq.empty()) { Vertex* v = pq.top(); pq.pop(); if (!v->isProcessed) { v->isProcessed = true; for (auto& e: v->adjacent) { Vertex* w = e.destination; int cvw = e.costs; if (cvw < 0) { throw runtime_error("Graph has negative edges"); } if (w->costs > v->costs + cvw) { w->costs = v->costs + cvw; w->previous = v; pq.push(w);

Dijkstra O(|E|•log|V|) Orde (van geoptimaliseerde code): Elke vertex wordt 1x bezocht . Daarbij worden alle adjacent vertexes bekeken en (mogelijk) wordt de destination in de priority_queue geplaatst. Voor het hele algoritme geldt dus (worst-case) O(|E|•log|E|) |V| < |E| < |V|2 ↔ log|V| < log|E| < log|V|2 ↔ log|V| < log|E| < 2•log|V| O(log|V|) < O(log|E|) < O(log|V|) ↔ O(log|E|) = O(log|V|) O(|E|•log|E|) ↔ O(|E|•log|V|)

Negative-weighted shortest path Bellman-Ford algoritme Het is nu niet meer mogelijk om elke vertex maar 1x te “bezoeken”. Een negative-cost cycle moet herkend worden. Telkens als costs van een vertex wordt aangepast moet deze vertex opnieuw “bezocht” worden. Als een vertex |V| keer bezocht is, is er negative-cost cycle aanwezig. Bellman-Ford: O(|E|•|V|)

Negative-weighted shortest path Zet start vertex in een queue. Zolang queue niet leeg: Haal vertex v uit queue. Als v |V| keer in de queue heeft gestaan rapporteer negative-cost cycle en stop Voor alle adjacent vertices w: Als costsw > costsv + costsv,w costsw = costsv + costsv,w Als w niet in de queue staat: Zet vertex w in de queue.

Negative-weighted shortest path Hulpvariabelen in Vertex: unsigned int timesQueued number of time that this Vertex is placed on the queue bool isOnQueue this Vertex is currently present on the queue

Bellman-Ford void Graph::negative(const string& startName) { reset(); Vertex* start = findVertex(startName); start->costs = 0; queue<Vertex*> q; q.push(start); start->isOnQueue = true; start->timesQueued += 1; // see next page

Bellman-Ford while (!q.empty()) { Vertex* v = q.front(); q.pop(); v->isOnQueue = false; if (v->timesQueued > vertices.size()) { throw runtime_error("Negative cycle detected"); } for (auto& e: v->adjacent) { Vertex* w = e.destination; int cvw = e.costs; if (w->costs > v->costs + cvw) { w->costs = v->costs + cvw; w->previous = v; w->timesQueued += 1; if (!w->isOnQueue) { w->isOnQueue = true; q.push(w);

Bellman-Ford 6 V0 V1 4 4 -3 4 V2 2 V4 V3 -2

Bellman-Ford previous costs costs ∞ ∞ 6 V1 V0 4 4 -3 4 2 -2 V4 costs ∞ ∞ 6 5 6 V0 V1 4 4 -3 4 V2 2 V3 -2 V4 costs ∞ 1 costs ∞ 5 costs ∞ 4 Enz: V3 = 2, V4 = 0, V1 = 4 V3 = 1, V4 = -1, V1 = 3 … 3 Helder  staat in de queue Vaag  staat niet meer in de queue

Acyclic shortest path Gebruik topological sort. Ev,w  V < W bereken de indegree van elke vertex (# binnenkomende edges) Herhaal tot alle vertices in de queue staan: Zoek vertex v met indegree == 0 en plaats v in de queue Voor alle adjacent vertices w: indegree w = indegree w + 1 De vertices in de queue zijn nu topological sorted. Bij het zoeken naar het kortste pad worden vertices in topological order “bezocht”: Elke vertex hoeft maar 1x bezocht te worden. Acyclic shortest path: O(|E|)

Acyclic shortest path void Graph::acyclic(const string& startName) { reset(); Vertex* start = findVertex(startName); start->costs = 0; queue<Vertex*> q; // calculate all indegrees for (auto& p : vertices) { for (auto& e : p.second->adjacent) { e.destination->indegree += 1; } // start with vertices with indegree 0 Vertex* v = p.second; if (v->indegree == 0) { q.push(v); // see next page

Acyclic shortest path // for all vertices in queue decltype (vertices.size()) iterations; for (iterations = 0; !q.empty(); ++iterations) { Vertex* v = q.front(); q.pop(); for (auto& e: v->adjacent) { Vertex* w = e.destination; int cvw = e.costs; w->indegree -= 1; if (w->indegree == 0) { q.push(w); } if (v->costs != INF && w->costs > v->costs + cvw) { w->costs = v->costs + cvw; w->previous = v; if (iterations != vertices.size()) { throw runtime_error("Graph has a cycle!");

Acyclic shortest path V0 2 V1 10 6 2 4 V4 V3 2 V2 8 5 6 V6 V5 1

Acyclic shortest path ∞ 2 1 ind = indegree previous 3 1 2 ind 1 costs 2 ind 1 costs 4 costs ∞ 6 ∞ V0 2 V1 10 6 2 4 V4 V3 2 costs 12 V2 ∞ costs ∞ 1 2 1 8 costs 5 10 ∞ 6 V6 V5 1 costs ∞ 6 costs ∞ 5

Shortest path algoritmen Breath-first Unweighted O(|E|) Acyclic Weighted, no cycles Dijkstra Weighted, no negative edges O(|E|•log|V|) Bellman-Ford Weighted O(|E|•|V|)

Galgje met find //... int main() { string w = "galgje"; set<string::size_type> v; do { for (string::size_type i = 0; i < w.size(); ++i) cout << (count(v.begin(), v.end(), i) ? w[i] : '.'); cout << endl << "Geef een letter: "; char c; cin >> c; auto r = w.begin(); while ((r = find(r, w.end(), c)) != w.end()) { v.insert(r - w.begin()); ++r; } while (v.size() != w.size()); cout << w << " is geraden!" << endl; 252

Galgje met sets (versie 1) //... int main() { string w = "galgje"; set<char> geraden, letters; copy(w.begin(), w.end(), inserter(letters, letters.begin())); do { for (auto c: w) cout << (geraden.count(c) ? c : '.'); cout << endl << "Raad een letter: "; char c; cin >> c; geraden.insert(c); } while (!includes(geraden.begin(), geraden.end(), letters.begin(), letters.end())); cout << w << " is geraden!" << endl; 253

Galgje met sets (versie 2) //... int main() { string w = "galgje"; set<char> goedGeraden, letters; copy(w.begin(), w.end(), inserter(letters, letters.begin())); do { for (auto c: w) cout << (geraden.count(c) ? c : '.'); cout << endl << "Raad een letter: "; char c; cin >> c; if (letters.count(c)) goedGeraden.insert(c); } while (goedGeraden != letters); cout << w << " is geraden!" << endl; 254

Galgje met strings //... int main() { string w = "galgje"; string geraden(w.length(), '.'); do { cout << geraden << endl << "Raad een letter: "; char c; cin >> c; for (string::size_type i = 0; i < w.length(); ++i) if (w[i] == c) geraden[i] = c; } while (geraden != w); cout << w << " is geraden!" << endl; 255

Galgje met strings en transform //... int main() { string w = "galgje"; string geraden(w.length(), '.'); do { cout << geraden << endl << "Raad een letter: "; char c; cin >> c; transform(w.begin(), w.end(), geraden.begin(), geraden.begin(), [c](char wc, char gc) { return c == wc ? wc : gc; }); } while (geraden != w); cout << w << " is geraden!" << endl; 256

Practicum opdracht 4 Wie opdracht 4b nog niet heeft ingeleverd moet de zaal verlaten!

Opdracht 4 met STL struct Freq: public map<string, int> { void init(string s) { (*this)[s] = 0; } void inc(string s) { if (count(s)) ++(*this)[s]; } void dec(string s) { if (count(s)) --(*this)[s]; } }; bool second_is_not_0(Freq::value_type p) { return p.second != 0; } bool second_abs_is_gt_1(Freq::value_type p) { return abs(p.second) > 1; } int main() { Freq f; ifstream f0("keywords.txt"), f1("in1.cpp"), f2("in2.cpp"); istream_iterator<string> if0(f0), if1(f1), if2(f2), iend; for_each(if0, iend, bind(mem_fn(&Freq::init), &f, _1)); for_each(if1, iend, bind(mem_fn(&Freq::inc), &f, _1)); for_each(if2, iend, bind(mem_fn(&Freq::dec), &f, _1)); cout << any_of(f.begin(), f.end(), second_abs_is_gt_1) << endl; cout << count_if(f.begin(), f.end(), second_is_not_0) << endl; cin.get(); return 0; }

Opdracht 4 met lamda int main() { map<string, int> f; ifstream f0("keywords.txt"), f1("in1.cpp"), f2("in2.cpp"); istream_iterator<string> if0(f0), if1(f1), if2(f2), iend; transform(if0, iend, inserter(f, f.end()), [](string s) { return make_pair(s, 0); }); for_each(if1, iend, [&](string w) { if (f.count(w)) ++f[w]; }); for_each(if2, iend, [&](string w) { if (f.count(w)) --f[w]; }); cout << any_of(f.cbegin(), f.cend(), [](const pair<const string, int>& p) { return abs(p.second) > 1; }) << endl; cout << count_if(f.cbegin(), f.cend(), [](const pair<const string, int>& p) { return p.second != 0; }) << endl; cin.get(); return 0; }

Opdracht 4 met lamda int main() { map<string, int> f; ifstream f0("keywords.txt"), f1("in1.cpp"), f2("in2.cpp"); istream_iterator<string> if0(f0), if1(f1), if2(f2), iend; for_each(if0, iend, [&](string w) { f[w] = 0; }); for_each(if1, iend, [&](string w) { if (f.count(w)) ++f[w]; }); for_each(if2, iend, [&](string w) { if (f.count(w)) --f[w]; }); cout << any_of(f.cbegin(), f.cend(), [](const pair<const string, int>& p) { return abs(p.second) > 1; }) << endl; cout << count_if(f.cbegin(), f.cend(), [](const pair<const string, int>& p) { return p.second != 0; }) << endl; cin.get(); return 0; }