├── .gitignore ├── LICENSE ├── Lesson1 ├── Activity01 │ └── Activity1.cpp ├── Activity02 │ └── Activity2.cpp ├── Activity03 │ └── Activity3.cpp ├── Exercise01 │ └── Exercise1.cpp ├── Exercise02 │ ├── Exercise2.cpp │ └── Exercise2_err.cpp ├── Exercise03 │ └── Exercise3.cpp ├── Exercise04 │ ├── Exercise4.cpp │ └── Exercise4_err.cpp ├── Exercise05 │ └── Exercise5.cpp └── Exercise06 │ └── Exercise6.cpp ├── Lesson2 ├── Activity04 │ └── Activity 4.cpp ├── Activity05 │ └── Activity 5.cpp ├── Exercise07 │ └── Exercise7.cpp ├── Exercise08 │ └── Exercise8.cpp ├── Exercise09 │ └── Exercise9.cpp ├── Exercise10 │ └── Exercise10.cpp ├── Exercise11 │ └── Exercise11.cpp └── Exercise12 │ └── Exercise12.cpp ├── Lesson3 ├── Activity06 │ └── Activity 6.cpp ├── Activity07 │ └── Activity 7.cpp ├── Exercise13 │ └── Exercise13.cpp ├── Exercise14 │ └── Exercise14.cpp ├── Exercise15 │ └── Exercise15.cpp ├── Exercise16 │ └── Exercise16.cpp └── Exercise17 │ └── Exercise17.cpp ├── Lesson4 ├── Activity08 │ └── vaccine.cpp ├── Activity09 │ └── partial_quicksort.cpp ├── Activity10 │ ├── mapreduce │ │ ├── LICENSE │ │ └── include │ │ │ ├── detail │ │ │ ├── datasource.hpp │ │ │ ├── hash_partitioner.hpp │ │ │ ├── intermediates.hpp │ │ │ ├── intermediates │ │ │ │ ├── in_memory.hpp │ │ │ │ └── local_disk.hpp │ │ │ ├── job.hpp │ │ │ ├── mergesort.hpp │ │ │ ├── null_combiner.hpp │ │ │ ├── platform.hpp │ │ │ ├── schedule_policy.hpp │ │ │ └── schedule_policy │ │ │ │ ├── cpu_parallel.hpp │ │ │ │ └── sequential.hpp │ │ │ └── mapreduce.hpp │ ├── mapreduce_wordcount.cpp │ └── mapreduce_wordcount_skeleton.cpp ├── CMakeLists.txt ├── Exercise18 │ ├── Chapter4.h │ └── binary_search.cpp ├── Exercise19 │ └── merge_sort.cpp ├── Exercise20 │ └── quick_sort.cpp ├── Exercise21 │ └── linear_time_select.cpp ├── Exercise22 │ └── transform_accumulate.cpp ├── Exercise23 │ ├── mapreduce │ │ ├── LICENSE │ │ └── include │ │ │ ├── detail │ │ │ ├── datasource.hpp │ │ │ ├── hash_partitioner.hpp │ │ │ ├── intermediates.hpp │ │ │ ├── intermediates │ │ │ │ ├── in_memory.hpp │ │ │ │ └── local_disk.hpp │ │ │ ├── job.hpp │ │ │ ├── mergesort.hpp │ │ │ ├── null_combiner.hpp │ │ │ ├── platform.hpp │ │ │ ├── schedule_policy.hpp │ │ │ └── schedule_policy │ │ │ │ ├── cpu_parallel.hpp │ │ │ │ └── sequential.hpp │ │ │ └── mapreduce.hpp │ └── mapreduce_primecheck.cpp ├── README.md └── testdata │ ├── file01.txt │ └── file02.txt ├── Lesson5 ├── Activity11 │ └── interval_scheduling_solution.cpp ├── Activity12 │ └── welsh_powell_solution.cpp ├── Exercise24 │ └── shortest_job_first.cpp ├── Exercise25 │ └── fractional_knapsack.cpp ├── Exercise26 │ └── kruskal.cpp └── Exercise27 │ └── graph_coloring.cpp ├── Lesson6 ├── Activity13 │ └── bipartite_check.cpp ├── Activity14 │ ├── USA-road-d.NY.gr │ └── nyshortest_path.cpp ├── Exercise28 │ └── bfs.cpp ├── Exercise29 │ └── dfs.cpp ├── Exercise30 │ └── prim.cpp └── Exercise31 │ └── dijkstra.cpp ├── Lesson7 ├── Activity15 │ └── Activity 15.cpp ├── Activity16 │ └── Activity 16.cpp ├── Activity17 │ └── Activity 17.cpp ├── Exercise32 │ └── Exercise32.cpp ├── Exercise33 │ └── Exercise33.cpp ├── Exercise34 │ └── Exercise34.cpp └── Exercise35 │ └── Exercise35.cpp ├── Lesson8 ├── Activity18 │ └── Activity 18.cp ├── Activity19 │ └── Activity 19.cpp ├── Activity20 │ └── Activity 20.cpp ├── Activity21 │ └── Activity 21.cp ├── Exercise36 │ └── Exercise36.cpp ├── Exercise37 │ └── Exercise37.cpp ├── Exercise38 │ └── Exercise38.cp ├── Exercise39 │ └── Exercise39.cp └── Exercise40 │ └── Exercise40.cpp ├── Lesson9 ├── Activity22 │ └── Activity22.cpp ├── Activity23 │ └── Activity 23 - Residential Roads.cpp ├── Exercise41 │ └── Exercise41.cpp ├── Exercise42 │ └── Exercise42.cpp ├── Exercise43 │ └── Exercise43.cpp └── Exercise44 │ └── Exercise44.cpp └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | Lesson4/build 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Training By Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Lesson1/Activity01/Activity1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | struct cir_list_node 5 | { 6 | T *data; 7 | cir_list_node *next, *prev; 8 | 9 | ~cir_list_node() 10 | { 11 | delete data; 12 | } 13 | }; 14 | 15 | template 16 | struct cir_list 17 | { 18 | public: 19 | using node = cir_list_node; 20 | using node_ptr = node*; 21 | 22 | private: 23 | node_ptr head; 24 | size_t n; 25 | 26 | public: 27 | cir_list() : n(0) 28 | { 29 | head = new node{NULL, NULL, NULL}; // Dummy node – having NULL data 30 | head->next = head; 31 | head->prev = head; 32 | } 33 | 34 | size_t size() const 35 | { 36 | return n; 37 | } 38 | 39 | void insert(const T &value) 40 | { 41 | node_ptr newNode = new node{new T(value), NULL, NULL}; 42 | n++; 43 | auto dummy = head->prev; 44 | dummy->next = newNode; 45 | newNode->prev = dummy; 46 | if (head == dummy) 47 | { 48 | dummy->prev = newNode; 49 | newNode->next = dummy; 50 | head = newNode; 51 | return; 52 | } 53 | newNode->next = head; 54 | head->prev = newNode; 55 | head = newNode; 56 | } 57 | 58 | void erase(const T &value) 59 | { 60 | auto cur = head, dummy = head->prev; 61 | while (cur != dummy) 62 | { 63 | if (*(cur->data) == value) 64 | { 65 | cur->prev->next = cur->next; 66 | cur->next->prev = cur->prev; 67 | if (cur == head) 68 | head = head->next; 69 | delete cur; 70 | n--; 71 | return; 72 | } 73 | cur = cur->next; 74 | } 75 | } 76 | 77 | struct cir_list_it 78 | { 79 | private: 80 | node_ptr ptr; 81 | 82 | public: 83 | cir_list_it(node_ptr p) : ptr(p) 84 | { 85 | } 86 | 87 | T &operator*() 88 | { 89 | return *(ptr->data); 90 | } 91 | 92 | node_ptr get() 93 | { 94 | return ptr; 95 | } 96 | 97 | cir_list_it &operator++() 98 | { 99 | ptr = ptr->next; 100 | return *this; 101 | } 102 | 103 | cir_list_it operator++(int) 104 | { 105 | cir_list_it it = *this; 106 | ++(*this); 107 | return it; 108 | } 109 | 110 | cir_list_it &operator--() 111 | { 112 | ptr = ptr->prev; 113 | return *this; 114 | } 115 | 116 | cir_list_it operator--(int) 117 | { 118 | cir_list_it it = *this; 119 | --(*this); 120 | return it; 121 | } 122 | 123 | friend bool operator==(const cir_list_it &it1, const cir_list_it &it2) 124 | { 125 | return it1.ptr == it2.ptr; 126 | } 127 | 128 | friend bool operator!=(const cir_list_it &it1, const cir_list_it &it2) 129 | { 130 | return it1.ptr != it2.ptr; 131 | } 132 | }; 133 | 134 | cir_list_it begin() 135 | { 136 | return cir_list_it{head}; 137 | } 138 | 139 | cir_list_it begin() const 140 | { 141 | return cir_list_it{head}; 142 | } 143 | 144 | cir_list_it end() 145 | { 146 | return cir_list_it{head->prev}; 147 | } 148 | 149 | cir_list_it end() const 150 | { 151 | return cir_list_it{head->prev}; 152 | } 153 | 154 | cir_list(const cir_list &other) : cir_list() 155 | { 156 | // Although, the following will insert the elements in reverse order, it won’t matter in logical sense since this is a circular list. 157 | for (const auto &i : other) 158 | insert(i); 159 | } 160 | 161 | cir_list(const std::initializer_list &il) : head(NULL), n(0) 162 | { 163 | // Although, the following will insert the elements in reverse order, it won’t matter in logical sense since this is a circular list. 164 | for (const auto &i : il) 165 | insert(i); 166 | } 167 | 168 | ~cir_list() 169 | { 170 | while (size()) 171 | { 172 | erase(*(head->data)); 173 | } 174 | } 175 | }; 176 | 177 | struct playlist 178 | { 179 | cir_list list; 180 | 181 | void insert(int song) 182 | { 183 | list.insert(song); 184 | } 185 | 186 | void erase(int song) 187 | { 188 | list.erase(song); 189 | } 190 | 191 | void loopOnce() 192 | { 193 | for (auto &song : list) 194 | std::cout << song << " "; 195 | std::cout << std::endl; 196 | } 197 | }; 198 | 199 | int main() 200 | { 201 | playlist pl; 202 | pl.insert(1); 203 | pl.insert(2); 204 | std::cout << "Playlist : "; 205 | pl.loopOnce(); 206 | 207 | playlist pl2 = pl; 208 | pl2.erase(2); 209 | pl2.insert(3); 210 | std::cout << "Second playlist : "; 211 | pl2.loopOnce(); 212 | } 213 | -------------------------------------------------------------------------------- /Lesson1/Activity02/Activity2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | struct card 10 | { 11 | int number; 12 | enum suit 13 | { 14 | HEART, 15 | SPADE, 16 | CLUB, 17 | DIAMOND 18 | } suit; 19 | 20 | std::string to_string() const 21 | { 22 | std::ostringstream os; 23 | if (number > 0 && number <= 10) 24 | os << number; 25 | else 26 | { 27 | switch (number) 28 | { 29 | case 1: 30 | os << "Ace"; 31 | break; 32 | case 11: 33 | os << "Jack"; 34 | break; 35 | case 12: 36 | os << "Queen"; 37 | break; 38 | case 13: 39 | os << "King"; 40 | break; 41 | default: 42 | return "Invalid card"; 43 | } 44 | } 45 | os << " of "; 46 | switch (suit) 47 | { 48 | case HEART: 49 | os << "hearts"; 50 | break; 51 | case SPADE: 52 | os << "spades"; 53 | break; 54 | case CLUB: 55 | os << "clubs"; 56 | break; 57 | case DIAMOND: 58 | os << "diamonds"; 59 | break; 60 | } 61 | return os.str(); 62 | } 63 | }; 64 | 65 | struct game 66 | { 67 | std::array deck; 68 | std::vector player1, player2, player3, player4; 69 | void buildDeck() 70 | { 71 | for (int i = 0; i < 13; i++) 72 | deck[i] = card{i + 1, card::HEART}; 73 | for (int i = 0; i < 13; i++) 74 | deck[i + 13] = card{i + 1, card::SPADE}; 75 | for (int i = 0; i < 13; i++) 76 | deck[i + 26] = card{i + 1, card::CLUB}; 77 | for (int i = 0; i < 13; i++) 78 | deck[i + 39] = card{i + 1, card::DIAMOND}; 79 | } 80 | 81 | void dealCards() 82 | { 83 | unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); 84 | std::shuffle(deck.begin(), deck.end(), std::default_random_engine(seed)); 85 | player1 = {deck.begin(), deck.begin() + 13}; 86 | player2 = {deck.begin() + 13, deck.begin() + 26}; 87 | player3 = {deck.begin() + 26, deck.begin() + 39}; 88 | player4 = {deck.begin() + 39, deck.end()}; 89 | } 90 | 91 | bool compareAndRemove(std::vector &p1, std::vector &p2) 92 | { 93 | if (p1.back().number == p2.back().number) 94 | { 95 | p1.pop_back(); 96 | p2.pop_back(); 97 | return true; 98 | } 99 | return false; 100 | } 101 | 102 | void playOneRound() 103 | { 104 | if (compareAndRemove(player1, player2)) 105 | { 106 | compareAndRemove(player3, player4); 107 | return; 108 | } 109 | else if (compareAndRemove(player1, player3)) 110 | { 111 | compareAndRemove(player2, player4); 112 | return; 113 | } 114 | else if (compareAndRemove(player1, player4)) 115 | { 116 | compareAndRemove(player2, player3); 117 | return; 118 | } 119 | else if (compareAndRemove(player2, player3)) 120 | { 121 | return; 122 | } 123 | else if (compareAndRemove(player2, player4)) 124 | { 125 | return; 126 | } 127 | else if (compareAndRemove(player3, player4)) 128 | { 129 | return; 130 | } 131 | unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); 132 | std::shuffle(player1.begin(), player1.end(), std::default_random_engine(seed)); 133 | std::shuffle(player2.begin(), player2.end(), std::default_random_engine(seed)); 134 | std::shuffle(player3.begin(), player3.end(), std::default_random_engine(seed)); 135 | std::shuffle(player4.begin(), player4.end(), std::default_random_engine(seed)); 136 | } 137 | 138 | bool isGameComplete() const 139 | { 140 | return player1.empty() || player2.empty() || player3.empty() || player4.empty(); 141 | } 142 | 143 | void playGame() 144 | { 145 | while (not isGameComplete()) 146 | { 147 | playOneRound(); 148 | } 149 | } 150 | 151 | int getWinner() const 152 | { 153 | if (player1.empty()) 154 | return 1; 155 | if (player2.empty()) 156 | return 2; 157 | if (player3.empty()) 158 | return 3; 159 | if (player4.empty()) 160 | return 4; 161 | } 162 | }; 163 | 164 | int main() 165 | { 166 | game newGame; 167 | newGame.buildDeck(); 168 | newGame.dealCards(); 169 | newGame.playGame(); 170 | auto winner = newGame.getWinner(); 171 | std::cout << "Player " << winner << " won the game." << std::endl; 172 | } 173 | -------------------------------------------------------------------------------- /Lesson1/Activity03/Activity3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Job 5 | { 6 | int id; 7 | std::string user; 8 | int time; 9 | static int count; 10 | 11 | public: 12 | Job(const std::string &u, int t) : user(u), time(t), id(++count) 13 | { 14 | } 15 | 16 | friend std::ostream &operator<<(std::ostream &os, const Job &j) 17 | { 18 | os << "id: " << j.id << ", user: " << j.user << ", time: " << j.time << " seconds" << std::endl; 19 | return os; 20 | } 21 | }; 22 | int Job::count = 0; 23 | 24 | template 25 | class Printer 26 | { 27 | std::queue jobs; 28 | 29 | public: 30 | bool addNewJob(const Job &job) 31 | { 32 | if (jobs.size() == N) 33 | return false; 34 | std::cout << "Added job in the queue: " << job; 35 | jobs.push(job); 36 | return true; 37 | } 38 | 39 | void startPrinting() 40 | { 41 | while (not jobs.empty()) 42 | { 43 | std::cout << "Processing job: " << jobs.front(); 44 | jobs.pop(); 45 | } 46 | } 47 | }; 48 | 49 | int main() 50 | { 51 | Printer<5> printer; 52 | 53 | Job j1("John", 10); 54 | Job j2("Jerry", 4); 55 | Job j3("Jimmy", 5); 56 | Job j4("George", 7); 57 | Job j5("Bill", 8); 58 | Job j6("Kenny", 10); 59 | 60 | printer.addNewJob(j1); 61 | printer.addNewJob(j2); 62 | printer.addNewJob(j3); 63 | printer.addNewJob(j4); 64 | printer.addNewJob(j5); 65 | 66 | if (not printer.addNewJob(j6)) // Can't add as queue is full. 67 | { 68 | std::cout << "Couldn't add 6th job" << std::endl; 69 | } 70 | 71 | printer.startPrinting(); 72 | 73 | printer.addNewJob(j6); // Can add now, as queue got emptied 74 | printer.startPrinting(); 75 | } 76 | -------------------------------------------------------------------------------- /Lesson1/Exercise01/Exercise1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | class dynamic_array 7 | { 8 | T *data; 9 | size_t n; 10 | 11 | public: 12 | dynamic_array(int n) 13 | { 14 | this->n = n; 15 | data = new T[n]; 16 | } 17 | 18 | dynamic_array(const dynamic_array &other) 19 | { 20 | n = other.n; 21 | data = new T[n]; 22 | 23 | for (int i = 0; i < n; i++) 24 | data[i] = other[i]; 25 | } 26 | 27 | T &operator[](int index) 28 | { 29 | return data[index]; 30 | } 31 | 32 | const T &operator[](int index) const 33 | { 34 | return data[index]; 35 | } 36 | 37 | T &at(int index) 38 | { 39 | if (index < n) 40 | return data[index]; 41 | throw "Index out of range"; 42 | } 43 | 44 | size_t size() const 45 | { 46 | return n; 47 | } 48 | 49 | ~dynamic_array() 50 | { 51 | delete[] data; // A destructor to prevent memory leak 52 | } 53 | 54 | T *begin() 55 | { 56 | return data; 57 | } 58 | 59 | const T *begin() const 60 | { 61 | return data; 62 | } 63 | 64 | T *end() 65 | { 66 | return data + n; 67 | } 68 | const T *end() const 69 | { 70 | return data + n; 71 | } 72 | 73 | friend dynamic_array operator+(const dynamic_array &arr1, dynamic_array &arr2) 74 | { 75 | dynamic_array result(arr1.size() + arr2.size()); 76 | std::copy(arr1.begin(), arr1.end(), result.begin()); 77 | std::copy(arr2.begin(), arr2.end(), result.begin() + arr1.size()); 78 | 79 | return result; 80 | } 81 | 82 | std::string to_string(const std::string &sep = ", ") 83 | { 84 | if (n == 0) 85 | return ""; 86 | std::ostringstream os; 87 | os << data[0]; 88 | 89 | for (int i = 1; i < n; i++) 90 | os << sep << data[i]; 91 | 92 | return os.str(); 93 | } 94 | }; 95 | 96 | struct student 97 | { 98 | std::string name; 99 | int standard; 100 | }; 101 | 102 | std::ostream &operator<<(std::ostream &os, const student &s) 103 | { 104 | return (os << "[Name: " << s.name << ", Standard: " << s.standard << "]"); 105 | } 106 | 107 | int main() 108 | { 109 | int nStudents; 110 | std::cout << "Enter number of students in class 1 : "; 111 | std::cin >> nStudents; 112 | 113 | dynamic_array class1(nStudents); 114 | for (int i = 0; i < nStudents; i++) 115 | { 116 | std::cout << "Enter name and class of student " << i + 1 << ": "; 117 | std::string name; 118 | int standard; 119 | std::cin >> name >> standard; 120 | class1[i] = student{name, standard}; 121 | } 122 | 123 | // Now, let’s try to access the student out of range in the array 124 | try 125 | { 126 | class1[nStudents] = student{ 127 | "John", 8}; // No exception, undefined behavior 128 | std::cout 129 | << "class1 student set out of range without exception" << std::endl; 130 | 131 | class1.at(nStudents) = student{ 132 | "John", 8}; // Will throw exception 133 | } 134 | catch (...) 135 | { 136 | std::cout << "Exception caught" << std::endl; 137 | } 138 | 139 | auto class2 = class1; // Deep copy 140 | 141 | std::cout << "Second class after initialized using first array : " << class2.to_string() << std::endl; 142 | 143 | auto class3 = class1 + class2; 144 | // Combines both classes and creates a bigger one 145 | 146 | std::cout << "Combined class : "; 147 | std::cout << class3.to_string() << std::endl; 148 | 149 | return 0; 150 | } 151 | -------------------------------------------------------------------------------- /Lesson1/Exercise02/Exercise2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | auto build_array(Args &&... args) -> std::array::type, sizeof...(args)> 7 | { 8 | using commonType = typename std::common_type::type; 9 | return {std::forward(args)...}; 10 | } 11 | 12 | int main() 13 | { 14 | auto data = build_array(1, 0u, 'a', 3.2f, false); 15 | for (auto i : data) 16 | std::cout << i << " "; 17 | std::cout << std::endl; 18 | } 19 | -------------------------------------------------------------------------------- /Lesson1/Exercise02/Exercise2_err.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | auto build_array(Args &&... args) -> std::array::type, sizeof...(args)> 7 | { 8 | using commonType = typename std::common_type::type; 9 | return {std::forward(args)...}; 10 | } 11 | 12 | int main() 13 | { 14 | auto data = build_array(1, 0u, 'a', 3.2f, false); 15 | for (auto i : data) 16 | std::cout << i << " "; 17 | std::cout << std::endl; 18 | 19 | auto data2 = build_array(1, "Packt", 2.0); 20 | } 21 | -------------------------------------------------------------------------------- /Lesson1/Exercise03/Exercise3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct citizen 5 | { 6 | std::string name; 7 | int age; 8 | }; 9 | 10 | std::ostream &operator<<(std::ostream &os, const citizen &c) 11 | { 12 | return (os << "[Name: " << c.name << ", Age: " << c.age << "]"); 13 | } 14 | 15 | int main() 16 | { 17 | std::forward_list citizens = {{"Raj", 22}, {"Rohit", 25}, {"Rohan", 17}, {"Sachin", 16}}; 18 | 19 | auto citizens_copy = citizens; 20 | 21 | std::cout << "All the citizens: "; 22 | for (const auto &c : citizens) 23 | std::cout << c << " "; 24 | std::cout << std::endl; 25 | 26 | citizens.remove_if( 27 | [](const citizen &c) { 28 | // Returns true if age is less than 18 29 | return (c.age < 18); 30 | }); 31 | 32 | std::cout << "Eligible citizens for voting: "; 33 | for (const auto &c : citizens) 34 | std::cout << c << " "; 35 | std::cout << std::endl; 36 | 37 | citizens_copy.remove_if( 38 | [](const citizen &c) { 39 | return (c.age != 17); 40 | }); 41 | 42 | std::cout << "Citizens that will be elgibile for voting next year: "; 43 | for (const auto &c : citizens_copy) 44 | std::cout << c << " "; 45 | std::cout << std::endl; 46 | } 47 | -------------------------------------------------------------------------------- /Lesson1/Exercise04/Exercise4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::vector vec = {"Lewis Hamilton", "Lewis Hamilton", "Nico Roseberg", "Sebastian Vettel", "Lewis Hamilton", "Sebastian Vettel", "Sebastian Vettel", "Sebastian Vettel", "Fernando Alonso"}; 8 | 9 | auto it = vec.begin(); // Constant time 10 | std::cout << "Latest winner is : " << *it << std::endl; 11 | 12 | it += 8; // Constant time 13 | std::cout << "Winner before 8 years was : " << *it << std::endl; 14 | 15 | advance(it, -3); // Constant time 16 | std::cout << "Winner before 3 years of that was : " << *it << std::endl; 17 | 18 | std::forward_list fwd(vec.begin(), vec.end()); 19 | 20 | auto it1 = fwd.begin(); 21 | std::cout << "Latest winner is : " << *it << std::endl; 22 | 23 | advance(it1, 5); // This takes linear time 24 | std::cout << "Winner before 5 years was : " << *it << std::endl; 25 | 26 | // Going back will result in compile time error as forward_list only allows us to move towards the end. 27 | // it1 += 2; // Compiler error 28 | } 29 | -------------------------------------------------------------------------------- /Lesson1/Exercise04/Exercise4_err.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::vector vec = {"Lewis Hamilton", "Lewis Hamilton", "Nico Roseberg", "Sebastian Vettel", "Lewis Hamilton", "Sebastian Vettel", "Sebastian Vettel", "Sebastian Vettel", "Fernando Alonso"}; 8 | 9 | auto it = vec.begin(); // Constant time 10 | std::cout << "Latest winner is : " << *it << std::endl; 11 | 12 | it += 8; // Constant time 13 | std::cout << "Winner before 8 years was : " << *it << std::endl; 14 | 15 | advance(it, -3); // Constant time 16 | std::cout << "Winner before 3 years of that was : " << *it << std::endl; 17 | 18 | std::forward_list fwd(vec.begin(), vec.end()); 19 | 20 | auto it1 = fwd.begin(); 21 | std::cout << "Latest winner is : " << *it << std::endl; 22 | 23 | advance(it1, 5); // This takes linear time 24 | std::cout << "Winner before 5 years was : " << *it << std::endl; 25 | 26 | // Going back will result in compile time error as forward_list only allows us to move towards the end. 27 | it1 += 2; // Compiler error 28 | } 29 | -------------------------------------------------------------------------------- /Lesson1/Exercise05/Exercise5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct singly_ll_node 5 | { 6 | int data; 7 | singly_ll_node *next; 8 | }; 9 | 10 | class singly_ll 11 | { 12 | public: 13 | using node = singly_ll_node; 14 | using node_ptr = node *; 15 | 16 | private: 17 | node_ptr head; 18 | 19 | public: 20 | void push_front(int val) 21 | { 22 | auto new_node = new node{val, NULL}; 23 | if (head != NULL) 24 | new_node->next = head; 25 | head = new_node; 26 | } 27 | 28 | void pop_front() 29 | { 30 | auto first = head; 31 | if (head) 32 | { 33 | head = head->next; 34 | delete first; 35 | } 36 | } 37 | 38 | struct singly_ll_iterator 39 | { 40 | private: 41 | node_ptr ptr; 42 | 43 | public: 44 | singly_ll_iterator(node_ptr p) : ptr(p) 45 | { 46 | } 47 | 48 | int &operator*() 49 | { 50 | return ptr->data; 51 | } 52 | 53 | node_ptr get() 54 | { 55 | return ptr; 56 | } 57 | 58 | singly_ll_iterator &operator++() // pre-increment 59 | { 60 | ptr = ptr->next; 61 | return *this; 62 | } 63 | 64 | singly_ll_iterator operator++(int) // post-increment 65 | { 66 | singly_ll_iterator result = *this; 67 | ++(*this); 68 | return result; 69 | } 70 | 71 | friend bool operator==(const singly_ll_iterator &left, const singly_ll_iterator &right) 72 | { 73 | return left.ptr == right.ptr; 74 | } 75 | 76 | friend bool operator!=(const singly_ll_iterator &left, const singly_ll_iterator &right) 77 | { 78 | return left.ptr != right.ptr; 79 | } 80 | }; 81 | 82 | singly_ll_iterator begin() 83 | { 84 | return singly_ll_iterator(head); 85 | } 86 | 87 | singly_ll_iterator end() 88 | { 89 | return singly_ll_iterator(NULL); 90 | } 91 | 92 | singly_ll_iterator begin() const 93 | { 94 | return singly_ll_iterator(head); 95 | } 96 | 97 | singly_ll_iterator end() const 98 | { 99 | return singly_ll_iterator(NULL); 100 | } 101 | 102 | singly_ll() = default; 103 | 104 | singly_ll(const singly_ll &other) : head(NULL) 105 | { 106 | if (other.head) 107 | { 108 | head = new node; 109 | auto cur = head; 110 | auto it = other.begin(); 111 | while (true) 112 | { 113 | cur->data = *it; 114 | 115 | auto tmp = it; 116 | ++tmp; 117 | if (tmp == other.end()) 118 | break; 119 | 120 | cur->next = new node; 121 | cur = cur->next; 122 | it = tmp; 123 | } 124 | } 125 | } 126 | 127 | singly_ll(const std::initializer_list &ilist) : head(NULL) 128 | { 129 | for (auto it = std::rbegin(ilist); it != std::rend(ilist); it++) 130 | push_front(*it); 131 | } 132 | }; 133 | 134 | int main() 135 | { 136 | singly_ll sll = {1, 2, 3}; 137 | sll.push_front(0); 138 | 139 | std::cout << "First list: "; 140 | for(auto i: sll) 141 | std::cout << i << " "; 142 | std::cout << std::endl; 143 | 144 | auto sll2 = sll; 145 | sll2.push_front(-1); 146 | std::cout << "Second list after copying from first list and inserting -1 in front: "; 147 | for(auto i: sll2) 148 | std::cout << i << ' '; // Prints -1 0 1 2 3 149 | std::cout << std::endl; 150 | 151 | std::cout << "First list after copying - deep copy: "; 152 | 153 | for(auto i: sll) 154 | std::cout << i << ' '; // Prints 0 1 2 3 155 | std::cout << std::endl; 156 | } 157 | -------------------------------------------------------------------------------- /Lesson1/Exercise06/Exercise6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | 7 | std::list list1 = {1, 2, 3, 4, 5}; 8 | list1.push_back(6); // list becomes {1, 2, 3, 4, 5, 6} 9 | list1.insert(next(list1.begin()), 0); // list becomes {1, 0, 2, 3, 4, 5, 6} 10 | list1.insert(list1.end(), 7); // list becomes {1, 0, 2, 3, 4, 5, 6, 7} 11 | 12 | list1.pop_back(); // list becomes {1, 0, 2, 3, 4, 5, 6} 13 | std::cout << "List after insertion & deletion functions : "; 14 | for (auto i : list1) 15 | std::cout << i << " "; 16 | } 17 | -------------------------------------------------------------------------------- /Lesson2/Activity05/Activity 5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct node 6 | { 7 | int data; 8 | int listPosition; 9 | int dataPosition; 10 | }; 11 | 12 | std::vector merge(const std::vector> &input) 13 | { 14 | auto comparator = [](const node &left, const node &right) { 15 | if (left.data == right.data) 16 | return left.listPosition > right.listPosition; 17 | return left.data > right.data; 18 | }; 19 | 20 | std::vector heap; 21 | for (int i = 0; i < input.size(); i++) 22 | { 23 | heap.push_back({input[i][0], i, 0}); 24 | std::push_heap(heap.begin(), heap.end(), comparator); 25 | } 26 | 27 | std::vector result; 28 | while (!heap.empty()) 29 | { 30 | std::pop_heap(heap.begin(), heap.end(), comparator); 31 | auto min = heap.back(); 32 | heap.pop_back(); 33 | 34 | result.push_back(min.data); 35 | int nextIndex = min.dataPosition + 1; 36 | if (nextIndex < input[min.listPosition].size()) 37 | { 38 | heap.push_back({input[min.listPosition][nextIndex], min.listPosition, nextIndex}); 39 | std::push_heap(heap.begin(), heap.end(), comparator); 40 | } 41 | } 42 | 43 | return result; 44 | } 45 | 46 | int main() 47 | { 48 | std::vector v1 = {1, 3, 8, 15, 105}; 49 | std::vector v2 = {2, 3, 10, 11, 16, 20, 25}; 50 | std::vector v3 = {-2, 100, 1000}; 51 | std::vector v4 = {-1, 0, 14, 18}; 52 | auto result = merge({v1, v2, v3, v4}); 53 | for (auto i : result) 54 | std::cout << i << ' '; 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /Lesson2/Exercise07/Exercise7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct node 5 | { 6 | std::string position; 7 | node *first, *second; 8 | }; 9 | 10 | struct org_tree 11 | { 12 | node *root; 13 | 14 | static org_tree create_org_structure(const std::string &pos) 15 | { 16 | org_tree tree; 17 | tree.root = new node{pos, NULL, NULL}; 18 | return tree; 19 | } 20 | 21 | static node *find(node *root, const std::string &value) 22 | { 23 | if (root == NULL) 24 | return NULL; 25 | if (root->position == value) 26 | return root; 27 | auto firstFound = org_tree::find(root->first, value); 28 | if (firstFound != NULL) 29 | return firstFound; 30 | return org_tree::find(root->second, value); 31 | } 32 | 33 | bool addSubordinate(const std::string &manager, const std::string &subordinate) 34 | { 35 | auto managerNode = org_tree::find(root, manager); 36 | if (!managerNode) 37 | { 38 | std::cout << "No position named " << manager << std::endl; 39 | return false; 40 | } 41 | if (managerNode->first && managerNode->second) 42 | { 43 | std::cout << manager << " already has 2 subordinates." << std::endl; 44 | return false; 45 | } 46 | if (!managerNode->first) 47 | managerNode->first = new node{subordinate, NULL, NULL}; 48 | else 49 | managerNode->second = new node{subordinate, NULL, NULL}; 50 | return true; 51 | } 52 | }; 53 | 54 | int main() 55 | { 56 | auto tree = org_tree::create_org_structure("CEO"); 57 | if (tree.addSubordinate("CEO", "Deputy Director")) 58 | std::cout << "Added Deputy Director in the tree." << std::endl; 59 | else 60 | std::cout << "Couldn't add Deputy Director in the tree" << std::endl; 61 | 62 | if (tree.addSubordinate("Deputy Director", "IT Head")) 63 | std::cout << "Added IT Head in the tree." << std::endl; 64 | else 65 | std::cout << "Couldn't add IT Head in the tree" << std::endl; 66 | 67 | if (tree.addSubordinate("Deputy Director", "Marketing Head")) 68 | std::cout << "Added Marketing Head in the tree." << std::endl; 69 | else 70 | std::cout << "Couldn't add Marketing Head in the tree" << std::endl; 71 | 72 | if (tree.addSubordinate("IT Head", "Security Head")) 73 | std::cout << "Added Security Head in the tree." << std::endl; 74 | else 75 | std::cout << "Couldn't add Security Head in the tree" << std::endl; 76 | 77 | if (tree.addSubordinate("IT Head", "App Development Head")) 78 | std::cout << "Added App Development Head in the tree." << std::endl; 79 | else 80 | std::cout << "Couldn't add App Development Head in the tree" << std::endl; 81 | 82 | if (tree.addSubordinate("Marketing Head", "Logistics Head")) 83 | std::cout << "Added Logistics Head in the tree." << std::endl; 84 | else 85 | std::cout << "Couldn't add Logistics Head in the tree" << std::endl; 86 | 87 | if (tree.addSubordinate("Marketing Head", "Public Relations Head")) 88 | std::cout << "Added Public Relations Head in the tree." << std::endl; 89 | else 90 | std::cout << "Couldn't add Public Relations Head in the tree" << std::endl; 91 | 92 | if (tree.addSubordinate("Deputy Director", "Finance Head")) 93 | std::cout << "Added Finance Head in the tree." << std::endl; 94 | else 95 | std::cout << "Couldn't add Finance Head in the tree" << std::endl; 96 | } 97 | -------------------------------------------------------------------------------- /Lesson2/Exercise08/Exercise8.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct node 5 | { 6 | std::string position; 7 | node *first, *second; 8 | }; 9 | 10 | struct org_tree 11 | { 12 | node *root; 13 | 14 | static org_tree create_org_structure(const std::string &pos) 15 | { 16 | org_tree tree; 17 | tree.root = new node{pos, NULL, NULL}; 18 | return tree; 19 | } 20 | 21 | static node *find(node *root, const std::string &value) 22 | { 23 | if (root == NULL) 24 | return NULL; 25 | if (root->position == value) 26 | return root; 27 | auto firstFound = org_tree::find(root->first, value); 28 | if (firstFound != NULL) 29 | return firstFound; 30 | return org_tree::find(root->second, value); 31 | } 32 | 33 | bool addSubordinate(const std::string &manager, const std::string &subordinate) 34 | { 35 | auto managerNode = org_tree::find(root, manager); 36 | if (!managerNode) 37 | { 38 | std::cout << "No position named " << manager << std::endl; 39 | return false; 40 | } 41 | if (managerNode->first && managerNode->second) 42 | { 43 | std::cout << manager << " already has 2 subordinates." << std::endl; 44 | return false; 45 | } 46 | if (!managerNode->first) 47 | managerNode->first = new node{subordinate, NULL, NULL}; 48 | else 49 | managerNode->second = new node{subordinate, NULL, NULL}; 50 | return true; 51 | } 52 | 53 | static void levelOrder(node *start) 54 | { 55 | if (!start) 56 | return; 57 | std::queue q; 58 | q.push(start); 59 | while (!q.empty()) 60 | { 61 | int size = q.size(); 62 | for (int i = 0; i < size; i++) 63 | { 64 | auto current = q.front(); 65 | q.pop(); 66 | std::cout << current->position << ", "; 67 | if (current->first) 68 | q.push(current->first); 69 | if (current->second) 70 | q.push(current->second); 71 | } 72 | std::cout << std::endl; 73 | } 74 | } 75 | }; 76 | 77 | int main() 78 | { 79 | auto tree = org_tree::create_org_structure("CEO"); 80 | if (tree.addSubordinate("CEO", "Deputy Director")) 81 | std::cout << "Added Deputy Director in the tree." << std::endl; 82 | else 83 | std::cout << "Couldn't add Deputy Director in the tree" << std::endl; 84 | 85 | if (tree.addSubordinate("Deputy Director", "IT Head")) 86 | std::cout << "Added IT Head in the tree." << std::endl; 87 | else 88 | std::cout << "Couldn't add IT Head in the tree" << std::endl; 89 | 90 | if (tree.addSubordinate("Deputy Director", "Marketing Head")) 91 | std::cout << "Added Marketing Head in the tree." << std::endl; 92 | else 93 | std::cout << "Couldn't add Marketing Head in the tree" << std::endl; 94 | 95 | if (tree.addSubordinate("IT Head", "Security Head")) 96 | std::cout << "Added Security Head in the tree." << std::endl; 97 | else 98 | std::cout << "Couldn't add Security Head in the tree" << std::endl; 99 | 100 | if (tree.addSubordinate("IT Head", "App Development Head")) 101 | std::cout << "Added App Development Head in the tree." << std::endl; 102 | else 103 | std::cout << "Couldn't add App Development Head in the tree" << std::endl; 104 | 105 | if (tree.addSubordinate("Marketing Head", "Logistics Head")) 106 | std::cout << "Added Logistics Head in the tree." << std::endl; 107 | else 108 | std::cout << "Couldn't add Logistics Head in the tree" << std::endl; 109 | 110 | if (tree.addSubordinate("Marketing Head", "Public Relations Head")) 111 | std::cout << "Added Public Relations Head in the tree." << std::endl; 112 | else 113 | std::cout << "Couldn't add Public Relations Head in the tree" << std::endl; 114 | 115 | if (tree.addSubordinate("Deputy Director", "Finance Head")) 116 | std::cout << "Added Finance Head in the tree." << std::endl; 117 | else 118 | std::cout << "Couldn't add Finance Head in the tree" << std::endl; 119 | 120 | org_tree::levelOrder(tree.root); 121 | } 122 | -------------------------------------------------------------------------------- /Lesson2/Exercise09/Exercise9.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct node 4 | { 5 | int data; 6 | node *left, *right; 7 | }; 8 | 9 | struct bst 10 | { 11 | node *root = nullptr; 12 | 13 | node *find(int value) 14 | { 15 | return find_impl(root, value); 16 | } 17 | 18 | private: 19 | node *find_impl(node *current, int value) 20 | { 21 | if (!current) 22 | { 23 | std::cout << std::endl; 24 | return NULL; 25 | } 26 | if (current->data == value) 27 | { 28 | std::cout << "Found " << value << std::endl; 29 | return current; 30 | } 31 | if (value < current->data) // Value will be in the left subtree 32 | { 33 | std::cout << "Going left from " << current->data << ", "; 34 | return find_impl(current->left, value); 35 | } 36 | // Value will be in the right subtree 37 | std::cout << "Going right from " << current->data << ", "; 38 | return find_impl(current->right, value); 39 | } 40 | 41 | public: 42 | void insert(int value) 43 | { 44 | if (!root) 45 | root = new node{value, NULL, NULL}; 46 | else 47 | insert_impl(root, value); 48 | } 49 | 50 | private: 51 | void insert_impl(node *current, int value) 52 | { 53 | if (value < current->data) 54 | { 55 | if (!current->left) 56 | current->left = new node{value, NULL, NULL}; 57 | else 58 | insert_impl(current->left, value); 59 | } 60 | else 61 | { 62 | if (!current->right) 63 | current->right = new node{value, NULL, NULL}; 64 | else 65 | insert_impl(current->right, value); 66 | } 67 | } 68 | 69 | public: 70 | void inorder() 71 | { 72 | inorder_impl(root); 73 | } 74 | 75 | private: 76 | void inorder_impl(node *start) 77 | { 78 | if (!start) 79 | return; 80 | inorder_impl(start->left); // Visit the left sub-tree 81 | std::cout << start->data << " "; // Print out the current node 82 | inorder_impl(start->right); // Visit the right sub-tree 83 | } 84 | 85 | public: 86 | node *successor(node *start) 87 | { 88 | auto current = start->right; 89 | while (current && current->left) 90 | current = current->left; 91 | return current; 92 | } 93 | 94 | void deleteValue(int value) 95 | { 96 | root = delete_impl(root, value); 97 | } 98 | 99 | private: 100 | node *delete_impl(node *start, int value) 101 | { 102 | if (!start) 103 | return NULL; 104 | if (value < start->data) 105 | start->left = delete_impl(start->left, value); 106 | else if (value > start->data) 107 | start->right = delete_impl(start->right, value); 108 | else 109 | { 110 | if (!start->left) // Either both children are absent or only left child is absent 111 | { 112 | auto tmp = start->right; 113 | delete start; 114 | return tmp; 115 | } 116 | if (!start->right) // Only right child is absent 117 | { 118 | auto tmp = start->left; 119 | delete start; 120 | return tmp; 121 | } 122 | 123 | auto succNode = successor(start); 124 | start->data = succNode->data; 125 | // Delete the successor from right subtree, since it will always be in the right subtree 126 | start->right = delete_impl(start->right, succNode->data); 127 | } 128 | return start; 129 | } 130 | }; 131 | 132 | int main() 133 | { 134 | bst tree; 135 | tree.insert(12); 136 | tree.insert(10); 137 | tree.insert(20); 138 | tree.insert(8); 139 | tree.insert(11); 140 | tree.insert(15); 141 | tree.insert(28); 142 | tree.insert(4); 143 | tree.insert(2); 144 | 145 | std::cout << "Inorder: "; 146 | tree.inorder(); // This will print all the elements in ascending order 147 | std::cout << std::endl; 148 | 149 | tree.deleteValue(12); 150 | std::cout << "Inorder after deleting 12: "; 151 | tree.inorder(); // This will print all the elements in ascending order 152 | std::cout << std::endl; 153 | 154 | if (tree.find(12)) 155 | std::cout << "Element 12 is present in the tree" << std::endl; 156 | else 157 | std::cout << "Element 12 is NOT present in the tree" << std::endl; 158 | } 159 | -------------------------------------------------------------------------------- /Lesson2/Exercise10/Exercise10.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct median 6 | { 7 | std::priority_queue maxHeap; 8 | std::priority_queue, std::greater> minHeap; 9 | 10 | void insert(int data) 11 | { 12 | if (maxHeap.size() == 0) 13 | { 14 | maxHeap.push(data); 15 | return; 16 | } 17 | 18 | if (maxHeap.size() == minHeap.size()) 19 | { 20 | if (data <= get()) 21 | maxHeap.push(data); 22 | else 23 | minHeap.push(data); 24 | return; 25 | } 26 | if (maxHeap.size() < minHeap.size()) 27 | { 28 | if (data > get()) 29 | { 30 | maxHeap.push(minHeap.top()); 31 | minHeap.pop(); 32 | minHeap.push(data); 33 | } 34 | else 35 | maxHeap.push(data); 36 | return; 37 | } 38 | if (data < get()) 39 | { 40 | minHeap.push(maxHeap.top()); 41 | maxHeap.pop(); 42 | maxHeap.push(data); 43 | } 44 | else 45 | minHeap.push(data); 46 | } 47 | 48 | double get() 49 | { 50 | if (maxHeap.size() == minHeap.size()) 51 | return (maxHeap.top() + minHeap.top()) / 2.0; 52 | if (maxHeap.size() < minHeap.size()) 53 | return minHeap.top(); 54 | return maxHeap.top(); 55 | } 56 | }; 57 | 58 | int main() 59 | { 60 | median med; 61 | med.insert(1); 62 | std::cout << "Median after insert 1: " << med.get() << std::endl; 63 | 64 | med.insert(5); 65 | std::cout << "Median after insert 5: " << med.get() << std::endl; 66 | 67 | med.insert(2); 68 | std::cout << "Median after insert 2: " << med.get() << std::endl; 69 | 70 | med.insert(10); 71 | std::cout << "Median after insert 10: " << med.get() << std::endl; 72 | 73 | med.insert(40); 74 | std::cout << "Median after insert 40: " << med.get() << std::endl; 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /Lesson2/Exercise11/Exercise11.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | enum class city : int 5 | { 6 | LONDON, 7 | MOSCOW, 8 | ISTANBUL, 9 | DUBAI, 10 | MUMBAI, 11 | SEATTLE, 12 | SINGAPORE 13 | }; 14 | 15 | std::ostream &operator<<(std::ostream &os, const city c) 16 | { 17 | switch (c) 18 | { 19 | case city::LONDON: 20 | os << "LONDON"; 21 | return os; 22 | case city::MOSCOW: 23 | os << "MOSCOW"; 24 | return os; 25 | case city::ISTANBUL: 26 | os << "ISTANBUL"; 27 | return os; 28 | case city::DUBAI: 29 | os << "DUBAI"; 30 | return os; 31 | case city::MUMBAI: 32 | os << "MUMBAI"; 33 | return os; 34 | case city::SEATTLE: 35 | os << "SEATTLE"; 36 | return os; 37 | case city::SINGAPORE: 38 | os << "SINGAPORE"; 39 | return os; 40 | default: 41 | return os; 42 | } 43 | } 44 | 45 | struct graph 46 | { 47 | std::vector> data; 48 | 49 | graph(int n) 50 | { 51 | data.reserve(n); 52 | std::vector row(n); 53 | std::fill(row.begin(), row.end(), -1); 54 | for (int i = 0; i < n; i++) 55 | { 56 | data.push_back(row); 57 | } 58 | } 59 | 60 | void addEdge(const city c1, const city c2, int dis) 61 | { 62 | std::cout << "ADD: " << c1 << "-" << c2 << "=" << dis << std::endl; 63 | 64 | auto n1 = static_cast(c1); 65 | auto n2 = static_cast(c2); 66 | data[n1][n2] = dis; 67 | data[n2][n1] = dis; 68 | } 69 | 70 | void removeEdge(const city c1, const city c2) 71 | { 72 | std::cout << "REMOVE: " << c1 << "-" << c2 << std::endl; 73 | 74 | auto n1 = static_cast(c1); 75 | auto n2 = static_cast(c2); 76 | data[n1][n2] = -1; 77 | data[n2][n1] = -1; 78 | } 79 | }; 80 | 81 | int main() 82 | { 83 | graph g(7); 84 | g.addEdge(city::LONDON, city::MOSCOW, 900); 85 | g.addEdge(city::LONDON, city::ISTANBUL, 500); 86 | g.addEdge(city::LONDON, city::DUBAI, 1000); 87 | g.addEdge(city::ISTANBUL, city::MOSCOW, 1000); 88 | g.addEdge(city::ISTANBUL, city::DUBAI, 500); 89 | g.addEdge(city::DUBAI, city::MUMBAI, 200); 90 | g.addEdge(city::ISTANBUL, city::SEATTLE, 1500); 91 | g.addEdge(city::DUBAI, city::SINGAPORE, 500); 92 | g.addEdge(city::MOSCOW, city::SEATTLE, 1000); 93 | g.addEdge(city::MUMBAI, city::SINGAPORE, 300); 94 | g.addEdge(city::SEATTLE, city::SINGAPORE, 700); 95 | 96 | g.addEdge(city::SEATTLE, city::LONDON, 1800); 97 | g.removeEdge(city::SEATTLE, city::LONDON); 98 | 99 | return 0; 100 | } 101 | -------------------------------------------------------------------------------- /Lesson2/Exercise12/Exercise12.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | enum class city : int 6 | { 7 | MOSCOW, 8 | LONDON, 9 | ISTANBUL, 10 | SEATTLE, 11 | DUBAI, 12 | MUMBAI, 13 | SINGAPORE 14 | }; 15 | 16 | std::ostream &operator<<(std::ostream &os, const city c) 17 | { 18 | switch (c) 19 | { 20 | case city::MOSCOW: 21 | os << "MOSCOW"; 22 | return os; 23 | case city::LONDON: 24 | os << "LONDON"; 25 | return os; 26 | case city::ISTANBUL: 27 | os << "ISTANBUL"; 28 | return os; 29 | case city::SEATTLE: 30 | os << "SEATTLE"; 31 | return os; 32 | case city::DUBAI: 33 | os << "DUBAI"; 34 | return os; 35 | case city::MUMBAI: 36 | os << "MUMBAI"; 37 | return os; 38 | case city::SINGAPORE: 39 | os << "SINGAPORE"; 40 | return os; 41 | default: 42 | return os; 43 | } 44 | } 45 | 46 | struct graph 47 | { 48 | std::vector>> data; 49 | 50 | graph(int n) 51 | { 52 | data = std::vector>>(n, std::vector>()); 53 | } 54 | 55 | void addEdge(const city c1, const city c2, int dis) 56 | { 57 | std::cout << "ADD: " << c1 << "-" << c2 << "=" << dis << std::endl; 58 | 59 | auto n1 = static_cast(c1); 60 | auto n2 = static_cast(c2); 61 | data[n1].push_back({n2, dis}); 62 | data[n2].push_back({n1, dis}); 63 | } 64 | 65 | void removeEdge(const city c1, const city c2) 66 | { 67 | std::cout << "REMOVE: " << c1 << "-" << c2 << std::endl; 68 | 69 | auto n1 = static_cast(c1); 70 | auto n2 = static_cast(c2); 71 | std::remove_if(data[n1].begin(), data[n1].end(), [n2](const auto &pair) { 72 | return pair.first == n2; 73 | }); 74 | std::remove_if(data[n2].begin(), data[n2].end(), [n1](const auto &pair) { 75 | return pair.first == n1; 76 | }); 77 | } 78 | }; 79 | 80 | int main() 81 | { 82 | graph g(7); 83 | g.addEdge(city::LONDON, city::MOSCOW, 900); 84 | g.addEdge(city::LONDON, city::ISTANBUL, 500); 85 | g.addEdge(city::LONDON, city::DUBAI, 1000); 86 | g.addEdge(city::ISTANBUL, city::MOSCOW, 1000); 87 | g.addEdge(city::ISTANBUL, city::DUBAI, 500); 88 | g.addEdge(city::DUBAI, city::MUMBAI, 200); 89 | g.addEdge(city::ISTANBUL, city::SEATTLE, 1500); 90 | g.addEdge(city::DUBAI, city::SINGAPORE, 500); 91 | g.addEdge(city::MOSCOW, city::SEATTLE, 1000); 92 | g.addEdge(city::MUMBAI, city::SINGAPORE, 300); 93 | g.addEdge(city::SEATTLE, city::SINGAPORE, 700); 94 | 95 | g.addEdge(city::SEATTLE, city::LONDON, 1800); 96 | g.removeEdge(city::SEATTLE, city::LONDON); 97 | 98 | return 0; 99 | } -------------------------------------------------------------------------------- /Lesson3/Activity06/Activity 6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct URLService 5 | { 6 | using ActualURL = std::string; 7 | using TinyURL = std::string; 8 | 9 | private: 10 | std::unordered_map data; 11 | 12 | public: 13 | std::pair lookup(const TinyURL &url) const 14 | { 15 | auto it = data.find(url); 16 | if (it == data.end()) // If small URL is not registered. 17 | { 18 | return std::make_pair(false, std::string()); 19 | } 20 | else 21 | { 22 | return std::make_pair(true, it->second); 23 | } 24 | } 25 | 26 | bool registerURL(const ActualURL &actualURL, const TinyURL &tinyURL) 27 | { 28 | auto found = lookup(tinyURL).first; 29 | if (found) 30 | { 31 | return false; 32 | } 33 | 34 | data[tinyURL] = actualURL; 35 | return true; 36 | } 37 | 38 | bool deregisterURL(const TinyURL &tinyURL) 39 | { 40 | auto found = lookup(tinyURL).first; 41 | if (found) 42 | { 43 | data.erase(tinyURL); 44 | return true; 45 | } 46 | 47 | return false; 48 | } 49 | 50 | void printURLs() const 51 | { 52 | for (const auto &entry : data) 53 | { 54 | std::cout << entry.first << " -> " << entry.second << std::endl; 55 | } 56 | std::cout << std::endl; 57 | } 58 | }; 59 | 60 | int main() 61 | { 62 | URLService service; 63 | 64 | if (service.registerURL("https://www.packtpub.com/eu/big-data-and-business-intelligence/machine-learning-r-third-edition", "https://ml-r-v3")) 65 | { 66 | std::cout << "Registered https: //ml-r-v3" << std::endl; 67 | } 68 | else 69 | { 70 | std::cout << "Couldn’t register https: //ml-r-v3" << std::endl; 71 | } 72 | 73 | if (service.registerURL("https://www.packtpub.com/eu/virtualization-and-cloud/hands-aws-penetration-testing-kali-linux", "https://aws-test-kali")) 74 | { 75 | std::cout << "Registered https: //aws-test-kali" << std::endl; 76 | } 77 | else 78 | { 79 | std::cout << "Couldn’t register https: //aws-test-kali" << std::endl; 80 | } 81 | 82 | if (service.registerURL("https://www.packtpub.com/eu/application-development/hands-qt-python-developers", "https://qt-python")) 83 | { 84 | std::cout << "Registered https: //qt-python" << std::endl; 85 | } 86 | else 87 | { 88 | std::cout << "Couldn’t register https: //qt-python" << std::endl; 89 | } 90 | 91 | auto findMLBook = service.lookup("https://ml-r-v3"); 92 | if (findMLBook.first) 93 | { 94 | std::cout << "Actual URL : " << findMLBook.second << std::endl; 95 | } 96 | else 97 | { 98 | std::cout << "Couldn’t find URL for book for ML." << std::endl; 99 | } 100 | 101 | auto findReactBook = service.lookup("https://react-cookbook"); 102 | if (findReactBook.first) 103 | { 104 | std::cout << "Actual URL : " << findReactBook.second << std::endl; 105 | } 106 | else 107 | { 108 | std::cout << "Couldn’t find URL for book for React." << std::endl; 109 | } 110 | 111 | if (service.deregisterURL("https://qt-python")) 112 | { 113 | std::cout << "Deregistered qt python link" << std::endl; 114 | } 115 | else 116 | { 117 | std::cout << "Couldn’t deregister qt python link" << std::endl; 118 | } 119 | 120 | auto findQtBook = service.lookup("https://qt-python"); 121 | if (findQtBook.first) 122 | { 123 | std::cout << "Actual URL : " << findQtBook.second << std::endl; 124 | } 125 | else 126 | { 127 | std::cout << "Couldn’t find Qt Python book" << std::endl; 128 | } 129 | 130 | std::cout << "List of registered URLs: " << std::endl; 131 | service.printURLs(); 132 | } 133 | -------------------------------------------------------------------------------- /Lesson3/Activity07/Activity 7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | class BloomFilter 7 | { 8 | int nHashes; 9 | std::vector bits; 10 | 11 | static constexpr int hashSize = 128 / 8; 12 | 13 | unsigned char hashValue[hashSize]; 14 | 15 | public: 16 | BloomFilter(int size, int hashes) : bits(size), nHashes(hashes) 17 | { 18 | if (nHashes > hashSize) 19 | { 20 | throw("Number of hash functions too high"); 21 | } 22 | 23 | if (size > 255) 24 | { 25 | throw("Size of bloom filter can't be >255"); 26 | } 27 | } 28 | 29 | void hash(const std::string &key) 30 | { 31 | MD5(reinterpret_cast(key.data()), key.length(), hashValue); 32 | } 33 | 34 | void add(const std::string &key) 35 | { 36 | hash(key); 37 | for (auto it = &hashValue[0]; it < &hashValue[nHashes]; it++) 38 | { 39 | bits[*it] = true; 40 | } 41 | std::cout << key << " added in bloom filter." << std::endl; 42 | } 43 | 44 | bool mayContain(const std::string &key) 45 | { 46 | hash(key); 47 | for (auto it = &hashValue[0]; it < &hashValue[nHashes]; it++) 48 | { 49 | if (!bits[*it]) 50 | { 51 | std::cout << key << " email can by used." << std::endl; 52 | return false; 53 | } 54 | } 55 | 56 | std::cout << key << " email is used by someone else." << std::endl; 57 | return true; 58 | } 59 | }; 60 | 61 | int main() 62 | { 63 | BloomFilter bloom(10, 15); 64 | 65 | bloom.add("abc@packt.com"); 66 | bloom.add("xyz@packt.com"); 67 | 68 | bloom.mayContain("abc"); 69 | bloom.mayContain("xyz@packt.com"); 70 | bloom.mayContain("xyz"); 71 | 72 | bloom.add("abcd@packt.com"); 73 | bloom.add("ab@packt.com"); 74 | 75 | bloom.mayContain("abcd"); 76 | bloom.mayContain("ab@packt.com"); 77 | } -------------------------------------------------------------------------------- /Lesson3/Exercise13/Exercise13.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using uint = unsigned int; 5 | class hash_map 6 | { 7 | std::vector data; 8 | 9 | public: 10 | hash_map(size_t n) 11 | { 12 | data = std::vector(n, -1); 13 | } 14 | 15 | void insert(uint value) 16 | { 17 | int n = data.size(); 18 | data[value % n] = value; 19 | std::cout << "Inserted " << value << std::endl; 20 | } 21 | 22 | bool find(uint value) 23 | { 24 | int n = data.size(); 25 | return (data[value % n] == value); 26 | } 27 | 28 | void erase(uint value) 29 | { 30 | int n = data.size(); 31 | if (data[value % n] == value) 32 | { 33 | data[value % n] = -1; 34 | std::cout << "Removed " << value << std::endl; 35 | } 36 | } 37 | }; 38 | 39 | int main() 40 | { 41 | hash_map map(7); 42 | 43 | auto print = [&](int value) { 44 | if (map.find(value)) 45 | std::cout << value << " found in the hash map"; 46 | else 47 | std::cout << value << " NOT found in the hash map"; 48 | std::cout << std::endl; 49 | }; 50 | 51 | map.insert(2); 52 | map.insert(25); 53 | map.insert(290); 54 | 55 | print(25); 56 | print(100); 57 | 58 | map.insert(100); 59 | print(100); 60 | map.erase(25); 61 | } 62 | -------------------------------------------------------------------------------- /Lesson3/Exercise14/Exercise14.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using uint = unsigned int; 7 | class hash_map 8 | { 9 | std::vector> data; 10 | 11 | public: 12 | hash_map(size_t n) 13 | { 14 | data.resize(n); 15 | } 16 | 17 | void insert(uint value) 18 | { 19 | int n = data.size(); 20 | data[value % n].push_back(value); 21 | std::cout << "Inserted " << value << std::endl; 22 | } 23 | 24 | bool find(uint value) 25 | { 26 | int n = data.size(); 27 | auto &entries = data[value % n]; 28 | return std::find(entries.begin(), entries.end(), value) != entries.end(); 29 | } 30 | 31 | void erase(uint value) 32 | { 33 | int n = data.size(); 34 | auto &entries = data[value % n]; 35 | auto iter = std::find(entries.begin(), entries.end(), value); 36 | 37 | if (iter != entries.end()) 38 | { 39 | entries.erase(iter); 40 | std::cout << "Removed " << value << std::endl; 41 | } 42 | } 43 | }; 44 | 45 | int main() 46 | { 47 | hash_map map(7); 48 | 49 | auto print = [&](int value) { 50 | if (map.find(value)) 51 | std::cout << value << " found in the hash map"; 52 | else 53 | std::cout << value << " NOT found in the hash map"; 54 | std::cout << std::endl; 55 | }; 56 | 57 | map.insert(2); 58 | map.insert(25); 59 | map.insert(290); 60 | 61 | map.insert(100); 62 | map.insert(55); 63 | 64 | print(100); 65 | map.erase(2); 66 | } 67 | -------------------------------------------------------------------------------- /Lesson3/Exercise15/Exercise15.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class hash_map 5 | { 6 | std::vector data1; 7 | std::vector data2; 8 | int size; 9 | 10 | int hash1(int key) const 11 | { 12 | return key % size; 13 | } 14 | 15 | int hash2(int key) const 16 | { 17 | return (key / size) % size; 18 | } 19 | 20 | public: 21 | hash_map(int n) : size(n) 22 | { 23 | data1 = std::vector(size, -1); 24 | data2 = std::vector(size, -1); 25 | } 26 | 27 | std::vector::iterator lookup(int key) 28 | { 29 | auto hash_value1 = hash1(key); 30 | if (data1[hash_value1] == key) 31 | { 32 | std::cout << "Found " << key << " in first table" << std::endl; 33 | return data1.begin() + hash_value1; 34 | } 35 | 36 | auto hash_value2 = hash2(key); 37 | if (data2[hash_value2] == key) 38 | { 39 | std::cout << "Found " << key << " in second table" << std::endl; 40 | return data2.begin() + hash_value2; 41 | } 42 | 43 | return data2.end(); 44 | } 45 | 46 | void erase(int key) 47 | { 48 | auto position = lookup(key); 49 | if (position != data2.end()) 50 | { 51 | *position = -1; 52 | std::cout << "Removed the element " << key << std::endl; 53 | } 54 | else 55 | { 56 | std::cout << "Key " << key << " not found." << std::endl; 57 | } 58 | } 59 | 60 | void insert(int key) 61 | { 62 | insert_impl(key, 0, 1); 63 | } 64 | 65 | void insert_impl(int key, int cnt, int table) 66 | { 67 | if (cnt >= size) 68 | { 69 | std::cout << "Cycle detected, while inserting " << key << ". Rehashing required." << std::endl; 70 | return; 71 | } 72 | 73 | if (table == 1) 74 | { 75 | int hash = hash1(key); 76 | if (data1[hash] == -1) 77 | { 78 | std::cout << "Inserted key " << key << " in table " << table << std::endl; 79 | data1[hash] = key; 80 | } 81 | else 82 | { 83 | int old = data1[hash]; 84 | data1[hash] = key; 85 | std::cout << "Inserted key " << key << " in table " << table << " by replacing " << old << std::endl; 86 | insert_impl(old, cnt + 1, 2); 87 | } 88 | } 89 | else 90 | { 91 | int hash = hash2(key); 92 | if (data2[hash] == -1) 93 | { 94 | std::cout << "Inserted key " << key << " in table " << table << std::endl; 95 | data2[hash] = key; 96 | } 97 | else 98 | { 99 | int old = data2[hash]; 100 | data2[hash] = key; 101 | std::cout << "Inserted key " << key << " in table " << table << " by replacing " << old << std::endl; 102 | insert_impl(old, cnt + 1, 2); 103 | } 104 | } 105 | } 106 | 107 | void print() 108 | { 109 | std::cout << "Index: "; 110 | for (int i = 0; i < size; i++) 111 | std::cout << i << '\t'; 112 | std::cout << std::endl; 113 | 114 | std::cout << "Data1: "; 115 | for (auto i : data1) 116 | std::cout << i << '\t'; 117 | std::cout << std::endl; 118 | 119 | std::cout << "Data2: "; 120 | for (auto i : data2) 121 | std::cout << i << '\t'; 122 | std::cout << std::endl; 123 | } 124 | }; 125 | 126 | int main() 127 | { 128 | hash_map map(7); 129 | map.print(); 130 | 131 | map.insert(10); 132 | map.insert(20); 133 | map.insert(30); 134 | std::cout << std::endl; 135 | 136 | map.insert(104); 137 | map.insert(2); 138 | map.insert(70); 139 | map.insert(9); 140 | map.insert(90); 141 | map.insert(2); 142 | map.insert(7); 143 | 144 | std::cout << std::endl; 145 | 146 | map.print(); 147 | 148 | std::cout << std::endl; 149 | 150 | map.insert(14); // This will cause cycle. 151 | } 152 | -------------------------------------------------------------------------------- /Lesson3/Exercise16/Exercise16.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void print(const std::unordered_set &container) 6 | { 7 | for (const auto &element : container) 8 | std::cout << element << " "; 9 | std::cout << std::endl; 10 | } 11 | 12 | void print(const std::unordered_map &container) 13 | { 14 | for (const auto &element : container) 15 | std::cout << element.first << ": " << element.second << ", "; 16 | std::cout << std::endl; 17 | } 18 | 19 | void find(const std::unordered_set &container, const auto &element) 20 | { 21 | if (container.find(element) == container.end()) 22 | std::cout << element << " not found" << std::endl; 23 | else 24 | std::cout << element << " found" << std::endl; 25 | } 26 | 27 | void find(const std::unordered_map &container, const auto &element) 28 | { 29 | auto it = container.find(element); 30 | if (it == container.end()) 31 | std::cout << element << " not found" << std::endl; 32 | else 33 | std::cout << element << " found with value =" << it->second << std::endl; 34 | } 35 | 36 | int main() 37 | { 38 | std::cout << "Set example : " << std::endl; 39 | std::unordered_set set1 = {1, 2, 3, 4, 5}; 40 | std::cout << "Initial set1 : "; 41 | print(set1); 42 | 43 | set1.insert(2); 44 | std::cout << "After inserting 2 : "; 45 | print(set1); 46 | 47 | set1.insert(10); 48 | set1.insert(351); 49 | std::cout << "After inserting 10 and 351 : "; 50 | print(set1); 51 | 52 | find(set1, 4); 53 | find(set1, 100); 54 | set1.erase(2); 55 | std::cout << "Erased 2 from set1" << std::endl; 56 | find(set1, 2); 57 | 58 | std::cout << "Map example : " << std::endl; 59 | std::unordered_map squareMap; 60 | 61 | squareMap.insert({2, 4}); 62 | squareMap[3] = 9; 63 | std::cout << "After inserting squares of 2 and 3 : "; 64 | print(squareMap); 65 | 66 | squareMap[30] = 900; 67 | squareMap[20] = 400; 68 | std::cout << "After inserting squares of 20 and 30 : "; 69 | print(squareMap); 70 | 71 | find(squareMap, 10); 72 | find(squareMap, 20); 73 | std::cout << "Value of map[3] =" << squareMap[3] << std::endl; 74 | std::cout << "Value of map[100] =" << squareMap[100] << std::endl; 75 | } 76 | -------------------------------------------------------------------------------- /Lesson3/Exercise17/Exercise17.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class bloom_filter 5 | { 6 | std::vector data; 7 | int nBits; 8 | 9 | int hash(int num, int key) 10 | { 11 | switch (num) 12 | { 13 | case 0: 14 | return key % nBits; 15 | case 1: 16 | return (key / 7) % nBits; 17 | case 2: 18 | return (key / 11) % nBits; 19 | } 20 | return 0; 21 | } 22 | 23 | public: 24 | bloom_filter(int n) : nBits(n) 25 | { 26 | data = std::vector(nBits, false); 27 | } 28 | 29 | void lookup(int key) 30 | { 31 | bool result = data[hash(0, key)] & data[hash(1, key)] & data[hash(2, key)]; 32 | if (result) 33 | { 34 | std::cout << key << " may be present." << std::endl; 35 | } 36 | else 37 | { 38 | std::cout << key << " is not present." << std::endl; 39 | } 40 | } 41 | 42 | void insert(int key) 43 | { 44 | data[hash(0, key)] = true; 45 | data[hash(1, key)] = true; 46 | data[hash(2, key)] = true; 47 | std::cout << key << " inserted." << std::endl; 48 | } 49 | }; 50 | 51 | int main() 52 | { 53 | bloom_filter bf(11); 54 | bf.insert(100); 55 | bf.insert(54); 56 | bf.insert(82); 57 | bf.lookup(5); 58 | bf.lookup(50); 59 | bf.lookup(2); 60 | bf.lookup(100); 61 | bf.lookup(8); 62 | bf.lookup(65); 63 | } 64 | -------------------------------------------------------------------------------- /Lesson4/Activity08/vaccine.cpp: -------------------------------------------------------------------------------- 1 | #include "Chapter4.h" 2 | 3 | class Student 4 | { 5 | private: 6 | std::pair name; 7 | bool vaccinated; 8 | 9 | public: 10 | // Constructor 11 | Student(std::pair n, bool v): 12 | name(n), vaccinated(v) 13 | {} 14 | 15 | // Getters 16 | auto get_name() { return name; } 17 | auto is_vaccinated() { return vaccinated; } 18 | 19 | // Two people are same if they have the same name 20 | bool operator ==(const Student& p) const 21 | { 22 | return this->name == p.name; 23 | } 24 | 25 | // The ordering of a set of people is defined by their name 26 | bool operator< (const Student& p) const 27 | { 28 | return this->name < p.name; 29 | } 30 | 31 | bool operator> (const Student& p) const 32 | { 33 | return this->name > p.name; 34 | } 35 | }; 36 | 37 | bool needs_vaccination(Student P, std::vector& people) 38 | { 39 | auto first = people.begin(); 40 | auto last = people.end(); 41 | 42 | while (true) 43 | { 44 | auto range_length = std::distance(first, last); 45 | auto mid_element_index = std::floor(range_length / 2); 46 | auto mid_element = *(first + mid_element_index); 47 | 48 | // Return true if the Student is found in the sequence and he's not vaccinated 49 | if (mid_element == P && mid_element.is_vaccinated() == false) 50 | return true; 51 | else if (mid_element == P && mid_element.is_vaccinated() == true) 52 | return false; 53 | else if (mid_element > P) 54 | std::advance(last, -mid_element_index); 55 | if (mid_element < P) 56 | std::advance(first, mid_element_index); 57 | 58 | // Student not found in the sequence and therefore should be vaccinated 59 | if (range_length == 1) 60 | return true; 61 | } 62 | } 63 | 64 | // Generate details of a random student with ID between 1 and max 65 | auto generate_random_Student(int max) 66 | { 67 | std::random_device rd; 68 | std::mt19937 rand(rd()); 69 | 70 | // the IDs of Student should be in range [1, max] 71 | std::uniform_int_distribution uniform_dist(1, max); 72 | 73 | // Generate random credentials 74 | auto random_name = std::make_pair(uniform_dist(rand), uniform_dist(rand)); 75 | bool is_vaccinated = uniform_dist(rand) % 2 ? true:false; 76 | 77 | return Student(random_name, is_vaccinated); 78 | } 79 | 80 | void search_test(int size, Student p) 81 | { 82 | std::vector people; 83 | 84 | // Create a list of random people 85 | for (auto i = 0; i < size; i++) 86 | people.push_back(generate_random_Student(size)); 87 | 88 | std::sort(people.begin(), people.end()); 89 | 90 | // To measure the time taken, start the clock 91 | std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); 92 | 93 | bool search_result = needs_vaccination(p, people); 94 | 95 | // Stop the clock 96 | std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); 97 | 98 | std::cout << "Time taken to search = " << 99 | std::chrono::duration_cast 100 | (end - begin).count() << " microseconds" << std::endl; 101 | 102 | if (search_result) 103 | std::cout << "Student (" << p.get_name().first << " " << p.get_name().second <<") " 104 | << "needs vaccination." << std::endl; 105 | else 106 | std::cout << "Student (" << p.get_name().first << " " << p.get_name().second << ") " 107 | << "does not need vaccination." << std::endl; 108 | } 109 | 110 | int main() 111 | { 112 | // Generate a Student to search 113 | auto p = generate_random_Student(1000); 114 | 115 | search_test(1000, p); 116 | search_test(10000, p); 117 | search_test(100000, p); 118 | 119 | return 0; 120 | } 121 | -------------------------------------------------------------------------------- /Lesson4/Activity09/partial_quicksort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | auto partition(typename std::vector::iterator begin, 9 | typename std::vector::iterator end) 10 | { 11 | auto pivot_val = *begin; 12 | auto left_iter = begin + 1; 13 | auto right_iter = end; 14 | 15 | while (true) 16 | { 17 | // Starting from the first element of vector, 18 | // find an element that is greater than pivot. 19 | while (*left_iter <= pivot_val && std::distance(left_iter, right_iter) > 0) 20 | left_iter++; 21 | 22 | // Starting from the end of vector moving to the beginning, 23 | // find an element that is lesser than the pivot. 24 | while (*right_iter > pivot_val && std::distance(left_iter, right_iter) > 0) 25 | right_iter--; 26 | 27 | // If left and right iterators meet, there are no elements left to swap. 28 | // Else, swap the elements pointed to by the left and right iterators 29 | if (left_iter == right_iter) 30 | break; 31 | else 32 | std::iter_swap(left_iter, right_iter); 33 | } 34 | if (pivot_val > *right_iter) 35 | std::iter_swap(begin, right_iter); 36 | 37 | return right_iter; 38 | } 39 | 40 | template 41 | void partial_quick_sort(typename std::vector::iterator begin, 42 | typename std::vector::iterator last, 43 | size_t k) 44 | { 45 | // If there are more than 1 elements in the vector 46 | if (std::distance(begin, last) >= 1) 47 | { 48 | // Apply the partition operation 49 | auto partition_iter = partition(begin, last); 50 | 51 | // Recursively sort the vectors created by the partition operation 52 | partial_quick_sort(begin, partition_iter-1, k); 53 | 54 | // Sort the right subvector only if the final position of pivot < k 55 | if(std::distance(begin, partition_iter) < k) 56 | partial_quick_sort(partition_iter, last, k); 57 | } 58 | } 59 | 60 | template 61 | void quick_sort(typename std::vector::iterator begin, 62 | typename std::vector::iterator last) 63 | { 64 | // If there are more than 1 elements in the vector 65 | if (std::distance(begin, last) >= 1) 66 | { 67 | // Apply the partition operation 68 | auto partition_iter = partition(begin, last); 69 | 70 | // Recursively sort the vectors created by the partition operation 71 | quick_sort(begin, partition_iter-1); 72 | quick_sort(partition_iter, last); 73 | } 74 | } 75 | 76 | template 77 | void print_vector(std::vector arr) 78 | { 79 | for (auto i : arr) 80 | std::cout << i << " "; 81 | 82 | std::cout << std::endl; 83 | } 84 | 85 | // Generates random vector of a given size with integers [1, size] 86 | template 87 | auto generate_random_vector(T size) 88 | { 89 | std::vector V; 90 | V.reserve(size); 91 | 92 | std::random_device rd; 93 | std::mt19937 rand(rd()); 94 | 95 | // the IDs of Student should be in range [1, max] 96 | std::uniform_int_distribution uniform_dist(1, size); 97 | 98 | for (T i = 0; i < size; i++) 99 | V.push_back(uniform_dist(rand)); 100 | 101 | return std::move(V); 102 | } 103 | 104 | // Sort the first K elements of a random vector of a given 'size' 105 | template 106 | void test_partial_quicksort(size_t size, size_t k) 107 | { 108 | // Create two copies of a random vector to use for the two algorithms 109 | auto random_vec = generate_random_vector(size); 110 | auto random_vec_copy(random_vec); 111 | 112 | std::cout << "Original vector: "<(random_vec); 114 | 115 | // Measure the time taken by partial quick sort 116 | std::chrono::steady_clock::time_point begin_qsort = std::chrono::steady_clock::now(); 117 | partial_quick_sort(random_vec.begin(), random_vec.end()-1, k); 118 | std::chrono::steady_clock::time_point end_qsort = std::chrono::steady_clock::now(); 119 | 120 | std::cout << std::endl << "Time taken by partial quick sort = " 121 | << std::chrono::duration_cast 122 | (end_qsort - begin_qsort).count() 123 | << " microseconds" << std::endl; 124 | 125 | std::cout << "Partially sorted vector (only first "<< k <<" elements):"; 126 | print_vector(random_vec); 127 | 128 | // Measure the time taken by partial quick sort 129 | begin_qsort = std::chrono::steady_clock::now(); 130 | quick_sort(random_vec_copy.begin(), random_vec_copy.end()-1); 131 | end_qsort = std::chrono::steady_clock::now(); 132 | 133 | std::cout << std::endl <<"Time taken by full quick sort = " 134 | << std::chrono::duration_cast 135 | (end_qsort - begin_qsort).count() 136 | << " microseconds" << std::endl; 137 | 138 | std::cout << "Fully sorted vector: "; 139 | print_vector(random_vec_copy); 140 | } 141 | 142 | int main() 143 | { 144 | test_partial_quicksort(100, 10); 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /Lesson4/Activity10/mapreduce/include/detail/hash_partitioner.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2016 Craig Henderson 2 | // https://github.com/cdmh/mapreduce 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace mapreduce { 9 | 10 | struct hash_partitioner 11 | { 12 | template 13 | size_t const operator()(T const &key, size_t partitions) const 14 | { 15 | boost::hash hasher; 16 | return hasher(key) % partitions; 17 | } 18 | }; 19 | 20 | } // namespace mapreduce 21 | 22 | // Permission is hereby granted, free of charge, to any person obtaining a copy 23 | // of this software and associated documentation files (the "Software"), to deal 24 | // in the Software without restriction, including without limitation the rights 25 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 26 | // copies of the Software, and to permit persons to whom the Software is 27 | // furnished to do so, subject to the following conditions: 28 | // 29 | // The above copyright notice and this permission notice shall be included in 30 | // all copies or substantial portions of the Software. 31 | // 32 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 33 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 34 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 35 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 36 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 37 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 38 | // THE SOFTWARE. 39 | -------------------------------------------------------------------------------- /Lesson4/Activity10/mapreduce/include/detail/intermediates.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2016 Craig Henderson 2 | // https://github.com/cdmh/mapreduce 3 | 4 | #include "hash_partitioner.hpp" 5 | #include "intermediates/in_memory.hpp" 6 | #include "intermediates/local_disk.hpp" 7 | 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /Lesson4/Activity10/mapreduce/include/detail/null_combiner.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2016 Craig Henderson 2 | // https://github.com/cdmh/mapreduce 3 | 4 | #pragma once 5 | 6 | namespace mapreduce { 7 | 8 | struct null_combiner 9 | { 10 | template 11 | static void run(IntermediateStore &/*intermediate_store*/) 12 | { 13 | } 14 | 15 | template 16 | void start(ReduceTaskKeyType const &) 17 | { } 18 | 19 | template 20 | void finish(ReduceTaskKeyType const &, IntermediateStore &) 21 | { } 22 | 23 | template 24 | void operator()(ReduceTaskKeyType const &) 25 | { } 26 | }; 27 | 28 | } // namespace mapreduce 29 | 30 | // Permission is hereby granted, free of charge, to any person obtaining a copy 31 | // of this software and associated documentation files (the "Software"), to deal 32 | // in the Software without restriction, including without limitation the rights 33 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 34 | // copies of the Software, and to permit persons to whom the Software is 35 | // furnished to do so, subject to the following conditions: 36 | // 37 | // The above copyright notice and this permission notice shall be included in 38 | // all copies or substantial portions of the Software. 39 | // 40 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 41 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 42 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 43 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 44 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 45 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 46 | // THE SOFTWARE. 47 | -------------------------------------------------------------------------------- /Lesson4/Activity10/mapreduce/include/detail/platform.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2016 Craig Henderson 2 | // https://github.com/cdmh/mapreduce 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #if defined(BOOST_WINDOWS) 10 | #include 11 | 12 | #if defined(BOOST_MSVC) 13 | #undef min 14 | #undef max 15 | #endif 16 | 17 | #ifdef __GNUC__ 18 | #include 19 | #endif 20 | 21 | namespace mapreduce { 22 | 23 | namespace win32 { 24 | 25 | namespace detail { 26 | 27 | template 28 | struct os_temporary_file_api_traits; 29 | 30 | template<> 31 | struct os_temporary_file_api_traits 32 | { 33 | static DWORD get_temp_path(DWORD length, char *buffer) 34 | { 35 | return GetTempPathA(length, buffer); 36 | } 37 | 38 | static unsigned get_temp_filename(char const *path, char const *prefix, unsigned unique, char *filename) 39 | { 40 | return GetTempFileNameA(path, prefix, unique, filename); 41 | } 42 | }; 43 | 44 | template<> 45 | struct os_temporary_file_api_traits 46 | { 47 | static DWORD get_temp_path(DWORD length, wchar_t *buffer) 48 | { 49 | return GetTempPathW(length, buffer); 50 | } 51 | 52 | static unsigned get_temp_filename(wchar_t const *path, wchar_t const *prefix, unsigned unique, wchar_t *filename) 53 | { 54 | return GetTempFileNameW(path, prefix, unique, filename); 55 | } 56 | }; 57 | 58 | } // namespace detail 59 | 60 | template 61 | std::basic_string &get_temporary_filename(std::basic_string &pathname) 62 | { 63 | Char path[_MAX_PATH+1]; 64 | if (!detail::os_temporary_file_api_traits::get_temp_path(sizeof(path)/sizeof(path[0]), path)) 65 | BOOST_THROW_EXCEPTION(boost::system::system_error(GetLastError(), boost::system::system_category())); 66 | 67 | Char file[_MAX_PATH+1]; 68 | if (!detail::os_temporary_file_api_traits::get_temp_filename(path, "mr_", 0, file)) 69 | BOOST_THROW_EXCEPTION(boost::system::system_error(GetLastError(), boost::system::system_category())); 70 | 71 | pathname = file; 72 | return pathname; 73 | } 74 | 75 | #else 76 | 77 | namespace mapreduce { 78 | 79 | namespace linux_os { 80 | 81 | std::string get_temporary_filename(std::string &pathname) 82 | { 83 | const std::string tmp = "/tmp/XXXXXX"; 84 | char* tmpfile = const_cast(tmp.c_str()); 85 | mkstemp(tmpfile); 86 | std::string res(tmpfile); 87 | return res; 88 | } 89 | 90 | #endif 91 | 92 | inline std::string const get_temporary_filename(void) 93 | { 94 | std::string filename; 95 | return get_temporary_filename(filename); 96 | } 97 | 98 | } // namespace win32/linux 99 | 100 | 101 | #if defined(_WIN32) 102 | namespace platform=win32; 103 | #elif defined(__GNUC__) 104 | namespace platform=linux_os; 105 | #else 106 | #error Undefined Platform 107 | #endif 108 | 109 | } // namespace mapreduce 110 | 111 | // Permission is hereby granted, free of charge, to any person obtaining a copy 112 | // of this software and associated documentation files (the "Software"), to deal 113 | // in the Software without restriction, including without limitation the rights 114 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 115 | // copies of the Software, and to permit persons to whom the Software is 116 | // furnished to do so, subject to the following conditions: 117 | // 118 | // The above copyright notice and this permission notice shall be included in 119 | // all copies or substantial portions of the Software. 120 | // 121 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 122 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 123 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 124 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 125 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 126 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 127 | // THE SOFTWARE. 128 | -------------------------------------------------------------------------------- /Lesson4/Activity10/mapreduce/include/detail/schedule_policy.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2016 Craig Henderson 2 | // https://github.com/cdmh/mapreduce 3 | 4 | #include "schedule_policy/sequential.hpp" 5 | #include "schedule_policy/cpu_parallel.hpp" 6 | 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /Lesson4/Activity10/mapreduce/include/detail/schedule_policy/sequential.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2016 Craig Henderson 2 | // https://github.com/cdmh/mapreduce 3 | 4 | #pragma once 5 | 6 | namespace mapreduce { 7 | 8 | namespace schedule_policy { 9 | 10 | namespace detail { 11 | 12 | struct null_lock 13 | { 14 | void lock(void) { } 15 | void unlock(void) { } 16 | }; 17 | 18 | } // namespace detail 19 | 20 | 21 | template 22 | class sequential 23 | { 24 | public: 25 | void operator()(Job &job, results &result) 26 | { 27 | map(job, result); 28 | intermediate(job, result); 29 | reduce(job, result); 30 | 31 | result.counters.actual_map_tasks = 1; 32 | result.counters.actual_reduce_tasks = 1; 33 | result.counters.num_result_files = job.number_of_partitions(); 34 | } 35 | 36 | void map(Job &job, results &result) 37 | { 38 | auto const start_time(std::chrono::system_clock::now()); 39 | 40 | typename Job::map_task_type::key_type *key = 0; 41 | detail::null_lock nolock; 42 | while (job.get_next_map_key(key) && job.run_map_task(key, result, nolock)) 43 | ; 44 | result.map_runtime = std::chrono::system_clock::now() - start_time; 45 | } 46 | 47 | void intermediate(Job &job, results &result) 48 | { 49 | auto const start_time(std::chrono::system_clock::now()); 50 | for (size_t partition=0; partition 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include -------------------------------------------------------------------------------- /Lesson4/Exercise18/binary_search.cpp: -------------------------------------------------------------------------------- 1 | #include "Chapter4.h" 2 | 3 | bool linear_search(int N, std::vector& S) 4 | { 5 | for (auto i : S) 6 | { 7 | if (i == N) 8 | return true; // Element found! 9 | } 10 | 11 | return false; 12 | } 13 | 14 | bool binary_search(int N, std::vector& S) 15 | { 16 | auto first = S.begin(); 17 | auto last = S.end(); 18 | 19 | while (true) 20 | { 21 | // Get the middle element of the current range 22 | auto range_length = std::distance(first, last); 23 | auto mid_element_index = std::floor(range_length / 2); 24 | auto mid_element = *(first + mid_element_index); 25 | 26 | // Compare the middle element of current range with N 27 | if (mid_element == N) 28 | return true; 29 | else if (mid_element > N) 30 | std::advance(last, -mid_element_index); 31 | if (mid_element < N) 32 | std::advance(first, mid_element_index); 33 | 34 | // If only one element left in the current range 35 | if (range_length == 1) 36 | return false; 37 | } 38 | } 39 | 40 | void run_small_search_test() 41 | { 42 | auto N = 2; 43 | std::vector S{ 1, 3, 2, 4, 5, 7, 9, 8, 6 }; 44 | 45 | std::sort(S.begin(), S.end()); 46 | 47 | if (linear_search(N, S)) 48 | std::cout << "Element found in set by linear search!" << std::endl; 49 | else 50 | std::cout << "Element not found." << std::endl; 51 | 52 | if (binary_search(N, S)) 53 | std::cout << "Element found in set by binary search!" << std::endl; 54 | else 55 | std::cout << "Element not found." << std::endl; 56 | } 57 | 58 | void run_large_search_test(int size, int N) 59 | { 60 | std::vector S; 61 | std::random_device rd; 62 | std::mt19937 rand(rd()); 63 | // distribution in range [1, size] 64 | std::uniform_int_distribution uniform_dist(1, size); 65 | 66 | // Insert random elements 67 | for (auto i = 0; i < size; i++) 68 | S.push_back(uniform_dist(rand)); 69 | 70 | std::sort(S.begin(), S.end()); 71 | 72 | // To measure the time taken, start the clock 73 | std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); 74 | 75 | bool search_result = binary_search(111, S); 76 | 77 | // Stop the clock 78 | std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); 79 | 80 | std::cout << "Time taken by binary search = " << 81 | std::chrono::duration_cast 82 | (end - begin).count() << std::endl; 83 | 84 | if (search_result) 85 | std::cout << "Element found in set!" << std::endl; 86 | else 87 | std::cout << "Element not found." << std::endl; 88 | } 89 | 90 | int main() 91 | { 92 | run_small_search_test(); 93 | 94 | run_large_search_test(100000, 36543); 95 | run_large_search_test(1000000, 36543); 96 | run_large_search_test(10000000, 36543); 97 | 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /Lesson4/Exercise19/merge_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | std::vector merge(std::vector& arr1, std::vector& arr2) 10 | { 11 | std::vector merged; 12 | 13 | auto iter1 = arr1.begin(); 14 | auto iter2 = arr2.begin(); 15 | 16 | while (iter1 != arr1.end() && iter2 != arr2.end()) 17 | { 18 | if (*iter1 < *iter2) 19 | { 20 | merged.emplace_back(*iter1); 21 | iter1++; 22 | } 23 | else 24 | { 25 | merged.emplace_back(*iter2); 26 | iter2++; 27 | } 28 | } 29 | 30 | if (iter1 != arr1.end()) 31 | { 32 | for (; iter1 != arr1.end(); iter1++) 33 | merged.emplace_back(*iter1); 34 | } 35 | else 36 | { 37 | for (; iter2 != arr2.end(); iter2++) 38 | merged.emplace_back(*iter2); 39 | } 40 | 41 | return merged; 42 | } 43 | 44 | template 45 | std::vector merge_sort(std::vector arr) 46 | { 47 | if (arr.size() > 1) 48 | { 49 | auto mid = size_t(arr.size() / 2); 50 | auto left_half = merge_sort(std::vector(arr.begin(), 51 | arr.begin() + mid)); 52 | auto right_half = merge_sort(std::vector(arr.begin() + mid, 53 | arr.end())); 54 | 55 | return merge(left_half, right_half); 56 | } 57 | 58 | return arr; 59 | } 60 | 61 | template 62 | void print_vector(std::vector arr) 63 | { 64 | for (auto i : arr) 65 | std::cout << i << " "; 66 | 67 | std::cout << std::endl; 68 | } 69 | 70 | void run_merge_sort_test() 71 | { 72 | std::vector S1{ 45, 1, 3, 1, 2, 3, 45, 5, 1, 2, 44, 5, 7 }; 73 | std::vector S2{ 45.6f, 1.0f, 3.8f, 1.01f, 2.2f, 3.9f, 45.3f, 5.5f, 1.0f, 2.0f, 44.0f, 5.0f, 7.0f }; 74 | std::vector S3{ 45.6, 1.0, 3.8 , 1.01, 2.2, 3.9, 45.3, 5.5, 1.0, 2.0, 44.0, 5.0, 7.0 }; 75 | std::vector C{ 'b','z','a','e','f','t','q','u','y' }; 76 | 77 | std::cout << "Unsorted arrays:" << std::endl; 78 | print_vector(S1); 79 | print_vector(S2); 80 | print_vector(S3); 81 | print_vector(C); 82 | std::cout << std::endl; 83 | 84 | auto sorted_S1 = merge_sort(S1); 85 | auto sorted_S2 = merge_sort(S2); 86 | auto sorted_S3 = merge_sort(S3); 87 | auto sorted_C = merge_sort(C); 88 | 89 | 90 | std::cout << "Arrays sorted using merge sort:" << std::endl; 91 | print_vector(sorted_S1); 92 | print_vector(sorted_S2); 93 | print_vector(sorted_S3); 94 | print_vector(sorted_C); 95 | std::cout << std::endl; 96 | } 97 | 98 | int main() 99 | { 100 | run_merge_sort_test(); 101 | return 0; 102 | } -------------------------------------------------------------------------------- /Lesson4/Exercise20/quick_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | auto partition(typename std::vector::iterator begin, 10 | typename std::vector::iterator end) 11 | { 12 | auto pivot_val = *begin; 13 | auto left_iter = begin + 1; 14 | auto right_iter = end; 15 | 16 | while (true) 17 | { 18 | // Starting from the first element of vector, 19 | // find an element that is greater than pivot. 20 | while (*left_iter <= pivot_val && std::distance(left_iter, right_iter) > 0) 21 | left_iter++; 22 | 23 | // Starting from the end of vector moving to the beginning, 24 | // find an element that is lesser than the pivot. 25 | while (*right_iter > pivot_val && std::distance(left_iter, right_iter) > 0) 26 | right_iter--; 27 | 28 | // If left and right iterators meet, there are no elements left to swap. 29 | // Else, swap the elements pointed to by the left and right iterators 30 | if (left_iter == right_iter) 31 | break; 32 | else 33 | std::iter_swap(left_iter, right_iter); 34 | } 35 | if (pivot_val > * right_iter) 36 | std::iter_swap(begin, right_iter); 37 | 38 | return right_iter; 39 | } 40 | 41 | template 42 | void quick_sort(typename std::vector::iterator begin, 43 | typename std::vector::iterator last) 44 | { 45 | // If there are more than 1 elements in the vector 46 | if (std::distance(begin, last) >= 1) 47 | { 48 | // Apply the partition operation 49 | auto partition_iter = partition(begin, last); 50 | 51 | // Recursively sort the vectors created by the partition operation 52 | quick_sort(begin, partition_iter - 1); 53 | quick_sort(partition_iter, last); 54 | } 55 | } 56 | 57 | 58 | template 59 | void print_vector(std::vector arr) 60 | { 61 | for (auto i : arr) 62 | std::cout << i << " "; 63 | 64 | std::cout << std::endl; 65 | } 66 | 67 | void run_quick_sort_test() 68 | { 69 | std::vector S1{ 45, 1, 3, 1, 2, 3, 45, 5, 1, 2, 44, 5, 7 }; 70 | std::vector S2{ 45.6, 1.0, 3.8 , 1.01, 2.2, 3.9, 45.3, 5.5, 1.0, 2.0, 44.0, 5.0, 7.0 }; 71 | std::vector S3{ 45.6, 1.0, 3.8 , 1.01, 2.2, 3.9, 45.3, 5.5, 1.0, 2.0, 44.0, 5.0, 7.0 }; 72 | std::vector C{ 'b','z','a','e','f','t','q','u','y' }; 73 | 74 | std::cout << "Unsorted arrays:" << std::endl; 75 | print_vector(S1); 76 | print_vector(S2); 77 | print_vector(S3); 78 | print_vector(C); 79 | std::cout << std::endl; 80 | 81 | // Called with arr.end() - 1 because the function expects an iterator to the last element of the vector 82 | quick_sort(S1.begin(), S1.end() - 1); 83 | quick_sort(S2.begin(), S2.end() - 1); 84 | quick_sort(S3.begin(), S3.end() - 1); 85 | quick_sort(C.begin(), C.end() - 1); 86 | 87 | 88 | std::cout << "Arrays sorted using quick sort:" << std::endl; 89 | print_vector(S1); 90 | print_vector(S2); 91 | print_vector(S3); 92 | print_vector(C); 93 | std::cout << std::endl; 94 | } 95 | 96 | int main() 97 | { 98 | run_quick_sort_test(); 99 | return 0; 100 | } -------------------------------------------------------------------------------- /Lesson4/Exercise22/transform_accumulate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void transform_test(size_t size) 9 | { 10 | std::vector S, Tr; 11 | std::random_device rd; 12 | std::mt19937 rand(rd()); 13 | // distribution in range [1, size] 14 | std::uniform_int_distribution uniform_dist(1, size); 15 | 16 | // Insert random elements 17 | for (auto i = 0; i < size; i++) 18 | S.push_back(uniform_dist(rand)); 19 | 20 | std::cout << "Map test== " << std::endl<< "Original array, S: "; 21 | for (auto i : S) 22 | std::cout << i << " "; 23 | std::cout << std::endl; 24 | 25 | // Transform 26 | std::transform(S.begin(), S.end(), std::back_inserter(Tr), [](int x) {return std::pow(x, 2.0); }); 27 | 28 | std::cout << "Transformed array, Tr: "; 29 | for (auto i : Tr) 30 | std::cout << i << " "; 31 | std::cout << std::endl; 32 | 33 | // For_each 34 | std::for_each(S.begin(), S.end(), [](int &x) {x = std::pow(x, 2.0); }); 35 | 36 | std::cout << "After applying for_each to S: "; 37 | for (auto i : S) 38 | std::cout << i << " "; 39 | std::cout << std::endl; 40 | } 41 | 42 | void reduce_test(size_t size) 43 | { 44 | std::vector S; 45 | std::random_device rd; 46 | std::mt19937 rand(rd()); 47 | std::uniform_int_distribution uniform_dist(1, size); 48 | 49 | // Insert random elements 50 | for (auto i = 0; i < size; i++) 51 | S.push_back(uniform_dist(rand)); 52 | 53 | std::cout << std::endl << "Reduce test== " << std::endl << "Original array, S: "; 54 | for (auto i : S) 55 | std::cout << i << " "; 56 | std::cout << std::endl; 57 | 58 | // Accumulate 59 | std::cout<<"std::accumulate() = " << std::accumulate(S.begin(), S.end(), 0, 60 | [](int acc, int x) { 61 | return acc+x; 62 | }); 63 | std::cout << std::endl; 64 | } 65 | 66 | 67 | int main() 68 | { 69 | transform_test(10); 70 | reduce_test(10); 71 | return 0; 72 | } -------------------------------------------------------------------------------- /Lesson4/Exercise23/mapreduce/include/detail/hash_partitioner.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2016 Craig Henderson 2 | // https://github.com/cdmh/mapreduce 3 | 4 | #pragma once 5 | 6 | #include 7 | 8 | namespace mapreduce { 9 | 10 | struct hash_partitioner 11 | { 12 | template 13 | size_t const operator()(T const &key, size_t partitions) const 14 | { 15 | boost::hash hasher; 16 | return hasher(key) % partitions; 17 | } 18 | }; 19 | 20 | } // namespace mapreduce 21 | 22 | // Permission is hereby granted, free of charge, to any person obtaining a copy 23 | // of this software and associated documentation files (the "Software"), to deal 24 | // in the Software without restriction, including without limitation the rights 25 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 26 | // copies of the Software, and to permit persons to whom the Software is 27 | // furnished to do so, subject to the following conditions: 28 | // 29 | // The above copyright notice and this permission notice shall be included in 30 | // all copies or substantial portions of the Software. 31 | // 32 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 33 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 34 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 35 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 36 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 37 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 38 | // THE SOFTWARE. 39 | -------------------------------------------------------------------------------- /Lesson4/Exercise23/mapreduce/include/detail/intermediates.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2016 Craig Henderson 2 | // https://github.com/cdmh/mapreduce 3 | 4 | #include "hash_partitioner.hpp" 5 | #include "intermediates/in_memory.hpp" 6 | #include "intermediates/local_disk.hpp" 7 | 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /Lesson4/Exercise23/mapreduce/include/detail/null_combiner.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2016 Craig Henderson 2 | // https://github.com/cdmh/mapreduce 3 | 4 | #pragma once 5 | 6 | namespace mapreduce { 7 | 8 | struct null_combiner 9 | { 10 | template 11 | static void run(IntermediateStore &/*intermediate_store*/) 12 | { 13 | } 14 | 15 | template 16 | void start(ReduceTaskKeyType const &) 17 | { } 18 | 19 | template 20 | void finish(ReduceTaskKeyType const &, IntermediateStore &) 21 | { } 22 | 23 | template 24 | void operator()(ReduceTaskKeyType const &) 25 | { } 26 | }; 27 | 28 | } // namespace mapreduce 29 | 30 | // Permission is hereby granted, free of charge, to any person obtaining a copy 31 | // of this software and associated documentation files (the "Software"), to deal 32 | // in the Software without restriction, including without limitation the rights 33 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 34 | // copies of the Software, and to permit persons to whom the Software is 35 | // furnished to do so, subject to the following conditions: 36 | // 37 | // The above copyright notice and this permission notice shall be included in 38 | // all copies or substantial portions of the Software. 39 | // 40 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 41 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 42 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 43 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 44 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 45 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 46 | // THE SOFTWARE. 47 | -------------------------------------------------------------------------------- /Lesson4/Exercise23/mapreduce/include/detail/platform.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2016 Craig Henderson 2 | // https://github.com/cdmh/mapreduce 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | 9 | #if defined(BOOST_WINDOWS) 10 | #include 11 | 12 | #if defined(BOOST_MSVC) 13 | #undef min 14 | #undef max 15 | #endif 16 | 17 | #ifdef __GNUC__ 18 | #include 19 | #endif 20 | 21 | namespace mapreduce { 22 | 23 | namespace win32 { 24 | 25 | namespace detail { 26 | 27 | template 28 | struct os_temporary_file_api_traits; 29 | 30 | template<> 31 | struct os_temporary_file_api_traits 32 | { 33 | static DWORD get_temp_path(DWORD length, char *buffer) 34 | { 35 | return GetTempPathA(length, buffer); 36 | } 37 | 38 | static unsigned get_temp_filename(char const *path, char const *prefix, unsigned unique, char *filename) 39 | { 40 | return GetTempFileNameA(path, prefix, unique, filename); 41 | } 42 | }; 43 | 44 | template<> 45 | struct os_temporary_file_api_traits 46 | { 47 | static DWORD get_temp_path(DWORD length, wchar_t *buffer) 48 | { 49 | return GetTempPathW(length, buffer); 50 | } 51 | 52 | static unsigned get_temp_filename(wchar_t const *path, wchar_t const *prefix, unsigned unique, wchar_t *filename) 53 | { 54 | return GetTempFileNameW(path, prefix, unique, filename); 55 | } 56 | }; 57 | 58 | } // namespace detail 59 | 60 | template 61 | std::basic_string &get_temporary_filename(std::basic_string &pathname) 62 | { 63 | Char path[_MAX_PATH+1]; 64 | if (!detail::os_temporary_file_api_traits::get_temp_path(sizeof(path)/sizeof(path[0]), path)) 65 | BOOST_THROW_EXCEPTION(boost::system::system_error(GetLastError(), boost::system::system_category())); 66 | 67 | Char file[_MAX_PATH+1]; 68 | if (!detail::os_temporary_file_api_traits::get_temp_filename(path, "mr_", 0, file)) 69 | BOOST_THROW_EXCEPTION(boost::system::system_error(GetLastError(), boost::system::system_category())); 70 | 71 | pathname = file; 72 | return pathname; 73 | } 74 | 75 | #else 76 | 77 | namespace mapreduce { 78 | 79 | namespace linux_os { 80 | 81 | std::string get_temporary_filename(std::string &pathname) 82 | { 83 | const std::string tmp = "/tmp/XXXXXX"; 84 | char* tmpfile = const_cast(tmp.c_str()); 85 | mkstemp(tmpfile); 86 | std::string res(tmpfile); 87 | return res; 88 | } 89 | 90 | #endif 91 | 92 | inline std::string const get_temporary_filename(void) 93 | { 94 | std::string filename; 95 | return get_temporary_filename(filename); 96 | } 97 | 98 | } // namespace win32/linux 99 | 100 | 101 | #if defined(_WIN32) 102 | namespace platform=win32; 103 | #elif defined(__GNUC__) 104 | namespace platform=linux_os; 105 | #else 106 | #error Undefined Platform 107 | #endif 108 | 109 | } // namespace mapreduce 110 | 111 | // Permission is hereby granted, free of charge, to any person obtaining a copy 112 | // of this software and associated documentation files (the "Software"), to deal 113 | // in the Software without restriction, including without limitation the rights 114 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 115 | // copies of the Software, and to permit persons to whom the Software is 116 | // furnished to do so, subject to the following conditions: 117 | // 118 | // The above copyright notice and this permission notice shall be included in 119 | // all copies or substantial portions of the Software. 120 | // 121 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 122 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 123 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 124 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 125 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 126 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 127 | // THE SOFTWARE. 128 | -------------------------------------------------------------------------------- /Lesson4/Exercise23/mapreduce/include/detail/schedule_policy.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2016 Craig Henderson 2 | // https://github.com/cdmh/mapreduce 3 | 4 | #include "schedule_policy/sequential.hpp" 5 | #include "schedule_policy/cpu_parallel.hpp" 6 | 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /Lesson4/Exercise23/mapreduce/include/detail/schedule_policy/sequential.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2009-2016 Craig Henderson 2 | // https://github.com/cdmh/mapreduce 3 | 4 | #pragma once 5 | 6 | namespace mapreduce { 7 | 8 | namespace schedule_policy { 9 | 10 | namespace detail { 11 | 12 | struct null_lock 13 | { 14 | void lock(void) { } 15 | void unlock(void) { } 16 | }; 17 | 18 | } // namespace detail 19 | 20 | 21 | template 22 | class sequential 23 | { 24 | public: 25 | void operator()(Job &job, results &result) 26 | { 27 | map(job, result); 28 | intermediate(job, result); 29 | reduce(job, result); 30 | 31 | result.counters.actual_map_tasks = 1; 32 | result.counters.actual_reduce_tasks = 1; 33 | result.counters.num_result_files = job.number_of_partitions(); 34 | } 35 | 36 | void map(Job &job, results &result) 37 | { 38 | auto const start_time(std::chrono::system_clock::now()); 39 | 40 | typename Job::map_task_type::key_type *key = 0; 41 | detail::null_lock nolock; 42 | while (job.get_next_map_key(key) && job.run_map_task(key, result, nolock)) 43 | ; 44 | result.map_runtime = std::chrono::system_clock::now() - start_time; 45 | } 46 | 47 | void intermediate(Job &job, results &result) 48 | { 49 | auto const start_time(std::chrono::system_clock::now()); 50 | for (size_t partition=0; partition 6 | 7 | #include 8 | #include "mapreduce.hpp" 9 | 10 | namespace prime_calculator { 11 | 12 | // Checks if a given number is prime using prime factorization 13 | bool const is_prime(long const number) 14 | { 15 | if (number > 2) 16 | { 17 | if (number % 2 == 0) 18 | return false; 19 | 20 | long const n = std::abs(number); 21 | long const sqrt_number = static_cast(std::sqrt(static_cast(n))); 22 | 23 | for (long i = 3; i <= sqrt_number; i += 2) 24 | { 25 | if (n % i == 0) 26 | return false; 27 | } 28 | } 29 | else if (number == 0 || number == 1) 30 | return false; 31 | 32 | return true; 33 | } 34 | 35 | // Defines a source of numbers, will be used to generate range of numbers between 36 | // first and last with a given step size 37 | template 38 | class number_source : mapreduce::detail::noncopyable 39 | { 40 | public: 41 | number_source(long first, long last, long step) 42 | : sequence_(0), first_(first), last_(last), step_(step) 43 | { 44 | } 45 | 46 | bool const setup_key(typename MapTask::key_type& key) 47 | { 48 | key = sequence_++; 49 | return (key * step_ <= last_); 50 | } 51 | 52 | bool const get_data(typename MapTask::key_type const& key, 53 | typename MapTask::value_type& value) 54 | { 55 | typename MapTask::value_type val; 56 | 57 | val.first = first_ + (key * step_); 58 | val.second = std::min(val.first + step_ - 1, last_); 59 | 60 | std::swap(val, value); 61 | return true; 62 | } 63 | 64 | private: 65 | long sequence_; 66 | long const step_; 67 | long const last_; 68 | long const first_; 69 | }; 70 | 71 | // Defines the Map stage 72 | struct map_task : public mapreduce::map_task > 73 | { 74 | template 75 | void operator()(Runtime& runtime, key_type const&/*key*/, value_type const& value) const 76 | { 77 | for (key_type loop = value.first; loop <= value.second; ++loop) 78 | runtime.emit_intermediate(is_prime(loop), loop); 79 | } 80 | }; 81 | 82 | // Defines the Reduce stage 83 | struct reduce_task : public mapreduce::reduce_task 84 | { 85 | template 86 | void operator()(Runtime& runtime, key_type const& key, It it, It ite) const 87 | { 88 | if (key) 89 | std::for_each(it, ite, std::bind(&Runtime::emit, &runtime, true, std::placeholders::_1)); 90 | } 91 | }; 92 | 93 | typedef 94 | mapreduce::job< 95 | prime_calculator::map_task, 96 | prime_calculator::reduce_task, 97 | mapreduce::null_combiner, 98 | prime_calculator::number_source> job; 99 | } // namespace prime_calculator 100 | 101 | int main(int argc, char* argv[]) 102 | { 103 | mapreduce::specification spec; 104 | 105 | int prime_limit = 1000; 106 | 107 | // Set number of threads to be used 108 | spec.map_tasks = std::max(1U, std::thread::hardware_concurrency()); 109 | spec.reduce_tasks = std::max(1U, std::thread::hardware_concurrency()); 110 | 111 | // Set the source of numbers in given range 112 | prime_calculator::job::datasource_type datasource(0, prime_limit, prime_limit / spec.reduce_tasks); 113 | 114 | std::cout << "\nCalculating Prime Numbers in the range 0 .. " << prime_limit << " ..." << std::endl; 115 | std::cout << std::endl << "Using " 116 | << std::max(1U, std::thread::hardware_concurrency()) << " CPU cores"; 117 | 118 | // Run mapreduce 119 | prime_calculator::job job(datasource, spec); 120 | mapreduce::results result; 121 | 122 | job.run >(result); 123 | 124 | std::cout << "\nMapReduce finished in " << result.job_runtime.count() << " seconds with " << std::distance(job.begin_results(), job.end_results()) << " results" << std::endl; 125 | 126 | // Print results 127 | for (auto it = job.begin_results(); it != job.end_results(); ++it) 128 | std::cout << it->second << " "; 129 | 130 | return 0; 131 | } 132 | 133 | // Permission is hereby granted, free of charge, to any person obtaining a copy 134 | // of this software and associated documentation files (the "Software"), to deal 135 | // in the Software without restriction, including without limitation the rights 136 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 137 | // copies of the Software, and to permit persons to whom the Software is 138 | // furnished to do so, subject to the following conditions: 139 | // 140 | // The above copyright notice and this permission notice shall be included in 141 | // all copies or substantial portions of the Software. 142 | // 143 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 144 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 145 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 146 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 147 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 148 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 149 | // THE SOFTWARE. -------------------------------------------------------------------------------- /Lesson4/README.md: -------------------------------------------------------------------------------- 1 | # How to compile code in this Lesson: 2 | 3 | ## On Linux/MacOS 4 | 1. Download and install CMake. 5 | 2. Run the following commands: 6 | ``` 7 | mkdir build && cd build 8 | cmake ../ 9 | make -j4 10 | ``` 11 | 12 | ## On Windows 13 | Open this directory in Visual Studio and click on Build All. 14 | -------------------------------------------------------------------------------- /Lesson4/testdata/file01.txt: -------------------------------------------------------------------------------- 1 | Hello World Goodbye World -------------------------------------------------------------------------------- /Lesson4/testdata/file02.txt: -------------------------------------------------------------------------------- 1 | Hello Hadoop Goodbye Hadoop -------------------------------------------------------------------------------- /Lesson5/Activity11/interval_scheduling_solution.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // Every task is represented as a pair 7 | struct Task 8 | { 9 | unsigned ID; 10 | unsigned start_time; 11 | unsigned end_time; 12 | }; 13 | 14 | auto initialize_tasks(size_t num_tasks) 15 | { 16 | std::random_device rd; 17 | std::mt19937 rand(rd()); 18 | std::uniform_int_distribution uniform_dist(1, num_tasks); 19 | 20 | // Create and initialize a set of tasks 21 | std::list tasks; 22 | 23 | for (unsigned i = 1; i <= num_tasks; i++) 24 | { 25 | auto start_time = uniform_dist(rand); 26 | auto duration = uniform_dist(rand); 27 | 28 | tasks.push_back({ i, start_time, start_time + duration }); 29 | } 30 | 31 | return tasks; 32 | } 33 | 34 | auto schedule(std::list tasks) 35 | { 36 | // Sort the list of tasks by their end times 37 | tasks.sort([](const auto& lhs, const auto& rhs) 38 | { return lhs.end_time < rhs.end_time; }); 39 | 40 | // Remove the tasks that interfere with one another 41 | for (auto curr_task = tasks.begin(); curr_task != tasks.end(); curr_task++) 42 | { 43 | // Point to the next task 44 | auto next_task = std::next(curr_task, 1); 45 | 46 | // While subsequent tasks interfere with the current task in iter 47 | while (next_task != tasks.end() && 48 | next_task->start_time < curr_task->end_time) 49 | { 50 | next_task = tasks.erase(next_task); 51 | } 52 | } 53 | 54 | return tasks; 55 | } 56 | 57 | void print(std::list& tasks) 58 | { 59 | std::cout << "Task ID \t Starting Time \t End time" << std::endl; 60 | 61 | for (auto t : tasks) 62 | std::cout << t.ID << "\t\t" << t.start_time << "\t\t" << t.end_time << std::endl; 63 | } 64 | 65 | void test_interval_scheduling(unsigned num_tasks) 66 | { 67 | auto tasks = initialize_tasks(num_tasks); 68 | 69 | std::cout << "Original list of tasks: " << std::endl; 70 | print(tasks); 71 | 72 | std::cout << "Scheduled tasks: " << std::endl; 73 | auto scheduled_tasks = schedule(tasks); 74 | print(scheduled_tasks); 75 | } 76 | 77 | int main() 78 | { 79 | test_interval_scheduling(20); 80 | return 0; 81 | } -------------------------------------------------------------------------------- /Lesson5/Activity12/welsh_powell_solution.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | template class Graph; 10 | 11 | template 12 | struct Edge 13 | { 14 | size_t src; 15 | size_t dest; 16 | T weight; 17 | 18 | // To compare edges, only compare their weights, 19 | // and not the source/destination vertices 20 | inline bool operator< (const Edge& e) const 21 | { 22 | return this->weight < e.weight; 23 | } 24 | 25 | inline bool operator> (const Edge& e) const 26 | { 27 | return this->weight > e.weight; 28 | } 29 | }; 30 | 31 | 32 | template 33 | std::ostream& operator<<(std::ostream& os, const Graph& G) 34 | { 35 | for (auto i = 1; i < G.vertices(); i++) 36 | { 37 | os << i << ":\t"; 38 | 39 | auto edges = G.outgoing_edges(i); 40 | for (auto& e : edges) 41 | os << "{" << e.dest << ": " << e.weight << "}, "; 42 | 43 | os << std::endl; 44 | } 45 | 46 | return os; 47 | } 48 | 49 | template 50 | class Graph 51 | { 52 | public: 53 | // Initialize the graph with N vertices 54 | Graph(size_t N) : V(N) 55 | {} 56 | 57 | // Return number of vertices in the graph 58 | auto vertices() const 59 | { 60 | return V; 61 | } 62 | 63 | // Return all edges in the graph 64 | auto& edges() const 65 | { 66 | return edge_list; 67 | } 68 | 69 | void add_edge(Edge&& e) 70 | { 71 | // Check if the source and destination vertices are within range 72 | if (e.src >= 1 && e.src <= V && 73 | e.dest >= 1 && e.dest <= V) 74 | edge_list.emplace_back(e); 75 | else 76 | std::cerr << "Vertex out of bounds" << std::endl; 77 | } 78 | 79 | // Returns all outgoing edges from vertex v 80 | auto outgoing_edges(size_t v) const 81 | { 82 | std::vector> edges_from_v; 83 | for (auto& e : edge_list) 84 | { 85 | if (e.src == v) 86 | edges_from_v.emplace_back(e); 87 | } 88 | return edges_from_v; 89 | } 90 | 91 | // Overloads the << operator so a graph be written directly to a stream 92 | // Can be used as std::cout << obj << std::endl; 93 | // template 94 | friend std::ostream& operator<< <>(std::ostream& os, const Graph& G); 95 | 96 | private: 97 | size_t V; // Stores number of vertices in graph 98 | std::vector> edge_list; 99 | }; 100 | 101 | 102 | 103 | // Initialize the colors that will be used to color the vertices 104 | std::unordered_map color_map = { 105 | {1, "Red"}, 106 | {2, "Blue"}, 107 | {3, "Green"}, 108 | {4, "Yellow"}, 109 | {5, "Black"}, 110 | {6, "White"} 111 | }; 112 | 113 | template 114 | auto welsh_powell_coloring(const Graph& G) 115 | { 116 | auto size = G.vertices(); 117 | std::vector> degrees; 118 | 119 | // Collect the degrees of vertices as pairs 120 | for (auto i = 1; i < size; i++) 121 | degrees.push_back(std::make_pair(i, G.outgoing_edges(i).size())); 122 | 123 | // Sort the vertices in decreasing order of degree 124 | std::sort(degrees.begin(), 125 | degrees.end(), 126 | [](const auto& a, const auto& b) 127 | { return a.second > b.second; }); 128 | 129 | std::cout << "The vertices will be colored in the following order: " << std::endl; 130 | std::cout << "Vertex ID \t Degree" << std::endl; 131 | for (auto const i : degrees) 132 | std::cout << i.first << "\t\t" << i.second << std::endl; 133 | 134 | std::vector assigned_colors(size); 135 | auto color_to_be_assigned = 1; 136 | 137 | while (true) 138 | { 139 | for (auto const i : degrees) 140 | { 141 | if (assigned_colors[i.first] != 0) 142 | continue; 143 | 144 | auto outgoing_edges = G.outgoing_edges(i.first); 145 | std::set neighbour_colors; 146 | 147 | // We assume that the graph is bidirectional 148 | for (auto e : outgoing_edges) 149 | { 150 | auto dest_color = assigned_colors[e.dest]; 151 | neighbour_colors.insert(dest_color); 152 | } 153 | 154 | if (neighbour_colors.find(color_to_be_assigned) == neighbour_colors.end()) 155 | assigned_colors[i.first] = color_to_be_assigned; 156 | } 157 | 158 | color_to_be_assigned++; 159 | 160 | // If there are no uncolored vertices left, exit 161 | if (std::find(assigned_colors.begin() + 1, assigned_colors.end(), 0) == 162 | assigned_colors.end()) 163 | break; 164 | } 165 | 166 | return assigned_colors; 167 | } 168 | 169 | void print_colors(std::vector& colors) 170 | { 171 | for (auto i = 1; i < colors.size(); i++) 172 | { 173 | std::cout << i << ": " << color_map[colors[i]] << std::endl; 174 | } 175 | } 176 | 177 | 178 | int main() 179 | { 180 | using T = unsigned; 181 | 182 | Graph G(9); 183 | 184 | std::map>> edges; 185 | edges[1] = { {2, 2}, {5, 3} }; 186 | edges[2] = { {1, 2}, {5, 5}, {4, 1} }; 187 | edges[3] = { {4, 2}, {7, 3} }; 188 | edges[4] = { {2, 1}, {3, 2}, {5, 2}, {6, 4}, {8, 5} }; 189 | edges[5] = { {1, 3}, {2, 5}, {4, 2}, {8, 3} }; 190 | edges[6] = { {4, 4}, {7, 4}, {8, 1} }; 191 | edges[7] = { {3, 3}, {6, 4} }; 192 | edges[8] = { {4, 5}, {5, 3}, {6, 1} }; 193 | 194 | for (auto& i : edges) 195 | for (auto& j : i.second) 196 | G.add_edge(Edge{ i.first, j.first, j.second }); 197 | std::cout << "Original Graph" << std::endl; 198 | std::cout << G; 199 | 200 | auto colors = welsh_powell_coloring(G); 201 | std::cout << "Vertex Colors: " << std::endl; 202 | print_colors(colors); 203 | return 0; 204 | } -------------------------------------------------------------------------------- /Lesson5/Exercise24/shortest_job_first.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | auto compute_waiting_times(std::vector& service_times) 9 | { 10 | std::vector W(service_times.size()); 11 | W[0] = 0; 12 | 13 | for (auto i = 1; i < service_times.size(); i++) 14 | W[i] = W[i - 1] + service_times[i - 1]; 15 | 16 | return W; 17 | } 18 | 19 | template 20 | void print_vector(std::vector& V) 21 | { 22 | for (auto& i : V) 23 | std::cout << i << " "; 24 | std::cout << std::endl; 25 | } 26 | 27 | template 28 | void compute_and_print_waiting_times(std::vector& service_times) 29 | { 30 | auto waiting_times = compute_waiting_times(service_times); 31 | 32 | std::cout << "Service times: " << std::endl; 33 | print_vector(service_times); 34 | 35 | std::cout << "Waiting times: " << std::endl; 36 | print_vector(waiting_times); 37 | 38 | std::cout << "Average waiting time = " 39 | << std::accumulate(waiting_times.begin(), waiting_times.end(), 0.0) / 40 | waiting_times.size(); 41 | 42 | std::cout<< std::endl; 43 | } 44 | 45 | void shortest_job_first(size_t size) 46 | { 47 | std::vector service_times; 48 | std::random_device rd; 49 | std::mt19937 rand(rd()); 50 | std::uniform_int_distribution uniform_dist(1, size); 51 | 52 | // Insert random elements as service times 53 | service_times.reserve(size); 54 | for (auto i = 0; i < size; i++) 55 | service_times.push_back(uniform_dist(rand)); 56 | 57 | compute_and_print_waiting_times(service_times); 58 | 59 | // Reorder the elements in the queue 60 | std::sort(service_times.begin(), service_times.end()); 61 | 62 | compute_and_print_waiting_times(service_times); 63 | } 64 | 65 | int main(int argc, char* argv[]) 66 | { 67 | shortest_job_first(10); 68 | } -------------------------------------------------------------------------------- /Lesson5/Exercise25/fractional_knapsack.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | template 10 | struct Object 11 | { 12 | using Wtype = weight_type; 13 | using Vtype = value_type; 14 | using Ftype = fractional_type; 15 | 16 | Wtype weight; 17 | Vtype value; 18 | Ftype value_per_unit_weight; 19 | 20 | // NOTE: The following overloads are to be used for std::sort() and I/O 21 | inline bool operator< (const Object& obj) const 22 | { 23 | // An object is better or worse than another object only on the 24 | // basis of its value per unit weight 25 | return this->value_per_unit_weight < obj.value_per_unit_weight; 26 | } 27 | 28 | inline bool operator== (const Object& obj) const 29 | { 30 | // An object is equivalent to another object only if 31 | // its value per unit weight is equal 32 | return this->value_per_unit_weight == obj.value_per_unit_weight; 33 | } 34 | 35 | // Overloads the << operator so an object can be written directly to a stream 36 | // e.g. Can be used as std::cout << obj << std::endl; 37 | template 40 | friend std::ostream& operator<<(std::ostream& os, const Object& obj); 41 | }; 42 | 43 | template 46 | std::ostream& operator<<(std::ostream& os, const Object& obj) 47 | { 48 | os << "Value: "< 58 | auto fill_knapsack(std::vector>& objects, 61 | weight_type knapsack_capacity) 62 | { 63 | 64 | std::vector> knapsack_contents; 65 | knapsack_contents.reserve(objects.size()); 66 | 67 | // Sort objects in the decreasing order 68 | std::sort(objects.begin(), objects.end()); 69 | std::reverse(objects.begin(), objects.end()); 70 | 71 | // Add the 'best' objects to the knapsack 72 | auto current_object = objects.begin(); 73 | weight_type current_total_weight = 0; 74 | while (current_total_weight <= knapsack_capacity && current_object != objects.end()) 75 | { 76 | knapsack_contents.push_back(*current_object); 77 | 78 | current_total_weight += current_object->weight; 79 | current_object++; 80 | } 81 | 82 | // Since the last object overflows the knapsack, adjust weight 83 | auto weight_of_last_obj_to_remove = current_total_weight - knapsack_capacity; 84 | 85 | knapsack_contents.back().weight -= weight_of_last_obj_to_remove; 86 | knapsack_contents.back().value -= knapsack_contents.back().value_per_unit_weight * 87 | weight_of_last_obj_to_remove; 88 | 89 | return knapsack_contents; 90 | } 91 | 92 | void test_fractional_knapsack(unsigned num_objects, unsigned knapsack_capacity) 93 | { 94 | using weight_type = unsigned; 95 | using value_type = double; 96 | using fractional_type = double; 97 | 98 | // Initialize the Random Number Generator 99 | std::random_device rd; 100 | std::mt19937 rand(rd()); 101 | std::uniform_int_distribution uniform_dist(1, num_objects); 102 | 103 | // Create a vector of objects 104 | std::vector> objects; 105 | objects.reserve(num_objects); 106 | for (auto i = 0; i < num_objects; i++) 107 | { 108 | // Every object is initialized with a random weight and value 109 | auto weight = uniform_dist(rand); 110 | auto value = uniform_dist(rand); 111 | auto obj = Object { 112 | static_cast(weight), 113 | static_cast(value), 114 | static_cast(value) / weight 115 | }; 116 | 117 | objects.push_back(obj); 118 | } 119 | 120 | // Display the set of objects 121 | std::cout << "Objects available: " << std::endl; 122 | for (auto& o : objects) 123 | std::cout << o << std::endl; 124 | std::cout << std::endl; 125 | 126 | // Arbitrarily assuming that the total knapsack capacity is 25 units 127 | auto solution = fill_knapsack(objects, knapsack_capacity); 128 | 129 | // Display items selected to be in the knapsack 130 | std::cout << "Objects selected to be in the knapsack (max capacity = " 131 | << knapsack_capacity<< "):" << std::endl; 132 | for (auto& o : solution) 133 | std::cout << o << std::endl; 134 | std::cout << std::endl; 135 | } 136 | 137 | int main(int argc, char* argv[]) 138 | { 139 | test_fractional_knapsack(10, 25); 140 | } -------------------------------------------------------------------------------- /Lesson5/Exercise27/graph_coloring.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template class Graph; 9 | 10 | template 11 | struct Edge 12 | { 13 | size_t src; 14 | size_t dest; 15 | T weight; 16 | 17 | // To compare edges, only compare their weights, 18 | // and not the source/destination vertices 19 | inline bool operator< (const Edge& e) const 20 | { 21 | return this->weight < e.weight; 22 | } 23 | 24 | inline bool operator> (const Edge& e) const 25 | { 26 | return this->weight > e.weight; 27 | } 28 | }; 29 | 30 | template 31 | std::ostream& operator<<(std::ostream& os, const Graph& G) 32 | { 33 | for (auto i = 1; i < G.vertices(); i++) 34 | { 35 | os << i << ":\t"; 36 | 37 | auto edges = G.outgoing_edges(i); 38 | for (auto& e : edges) 39 | os << "{" << e.dest << ": " << e.weight << "}, "; 40 | 41 | os << std::endl; 42 | } 43 | 44 | return os; 45 | } 46 | 47 | template 48 | class Graph 49 | { 50 | public: 51 | // Initialize the graph with N vertices 52 | Graph(size_t N) : V(N) 53 | {} 54 | 55 | // Return number of vertices in the graph 56 | auto vertices() const 57 | { 58 | return V; 59 | } 60 | 61 | // Return all edges in the graph 62 | auto& edges() const 63 | { 64 | return edge_list; 65 | } 66 | 67 | void add_edge(Edge&& e) 68 | { 69 | // Check if the source and destination vertices are within range 70 | if (e.src >= 1 && e.src <= V && 71 | e.dest >= 1 && e.dest <= V) 72 | edge_list.emplace_back(e); 73 | else 74 | std::cerr << "Vertex out of bounds" << std::endl; 75 | } 76 | 77 | // Returns all outgoing edges from vertex v 78 | auto outgoing_edges(size_t v) const 79 | { 80 | std::vector> edges_from_v; 81 | for (auto& e : edge_list) 82 | { 83 | if (e.src == v) 84 | edges_from_v.emplace_back(e); 85 | } 86 | return edges_from_v; 87 | } 88 | 89 | // Overloads the << operator so a graph be written directly to a stream 90 | // Can be used as std::cout << obj << std::endl; 91 | // template 92 | friend std::ostream& operator<< <> (std::ostream& os, const Graph& G); 93 | 94 | private: 95 | size_t V; // Stores number of vertices in graph 96 | std::vector> edge_list; 97 | }; 98 | 99 | // Initialize the colors that will be used to color the vertices 100 | std::unordered_map color_map = { 101 | {1, "Red"}, 102 | {2, "Blue"}, 103 | {3, "Green"}, 104 | {4, "Yellow"}, 105 | {5, "Black"}, 106 | {6, "White"} 107 | }; 108 | 109 | template 110 | auto greedy_coloring(const Graph& G) 111 | { 112 | auto size = G.vertices(); 113 | std::vector assigned_colors(size); 114 | 115 | // Let us start with vertex number 1. 116 | // Note that this choice is arbirary. 117 | for (auto i = 1; i < size; i++) 118 | { 119 | auto outgoing_edges = G.outgoing_edges(i); 120 | std::set neighbour_colors; 121 | 122 | for (auto e : outgoing_edges) 123 | { 124 | auto dest_color = assigned_colors[e.dest]; 125 | neighbour_colors.insert(dest_color); 126 | } 127 | 128 | // Find the smallest unassigned color 129 | // that is not currently used by any neighbour 130 | auto smallest_unassigned_color = 1; 131 | for (; 132 | smallest_unassigned_color <= color_map.size(); 133 | smallest_unassigned_color++) 134 | { 135 | if (neighbour_colors.find(smallest_unassigned_color) == 136 | neighbour_colors.end()) 137 | break; 138 | } 139 | 140 | assigned_colors[i] = smallest_unassigned_color; 141 | } 142 | 143 | return assigned_colors; 144 | } 145 | 146 | void print_colors(std::vector& colors) 147 | { 148 | for (auto i=1; i G(9); 160 | 161 | std::map>> edges; 162 | edges[1] = { {2, 2}, {5, 3} }; 163 | edges[2] = { {1, 2}, {5, 5}, {4, 1} }; 164 | edges[3] = { {4, 2}, {7, 3} }; 165 | edges[4] = { {2, 1}, {3, 2}, {5, 2}, {6, 4}, {8, 5} }; 166 | edges[5] = { {1, 3}, {2, 5}, {4, 2}, {8, 3} }; 167 | edges[6] = { {4, 4}, {7, 4}, {8, 1} }; 168 | edges[7] = { {3, 3}, {6, 4} }; 169 | edges[8] = { {4, 5}, {5, 3}, {6, 1} }; 170 | 171 | for (auto& i : edges) 172 | for (auto& j : i.second) 173 | G.add_edge(Edge{ i.first, j.first, j.second }); 174 | 175 | std::cout << "Original Graph: " << std::endl; 176 | std::cout << G << std::endl; 177 | 178 | auto colors = greedy_coloring(G); 179 | std::cout << "Vertex Colors: " << std::endl; 180 | print_colors(colors); 181 | 182 | return 0; 183 | } -------------------------------------------------------------------------------- /Lesson6/Activity13/bipartite_check.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template class Graph; 9 | 10 | template 11 | struct Edge 12 | { 13 | size_t src; 14 | size_t dest; 15 | T weight; 16 | 17 | // To compare edges, only compare their weights, 18 | // and not the source/destination vertices 19 | inline bool operator< (const Edge& e) const 20 | { 21 | return this->weight < e.weight; 22 | } 23 | 24 | inline bool operator> (const Edge& e) const 25 | { 26 | return this->weight > e.weight; 27 | } 28 | }; 29 | 30 | template 31 | std::ostream& operator<<(std::ostream& os, const Graph& G) 32 | { 33 | for (auto i = 1; i < G.vertices(); i++) 34 | { 35 | os << i << ":\t"; 36 | 37 | auto edges = G.outgoing_edges(i); 38 | for (auto& e : edges) 39 | os << "{" << e.dest << ": " << e.weight << "}, "; 40 | 41 | os << std::endl; 42 | } 43 | 44 | return os; 45 | } 46 | 47 | template 48 | class Graph 49 | { 50 | public: 51 | // Initialize the graph with N vertices 52 | Graph(size_t N) : V(N) 53 | {} 54 | 55 | // Return number of vertices in the graph 56 | auto vertices() const 57 | { 58 | return V; 59 | } 60 | 61 | // Return all edges in the graph 62 | auto& edges() const 63 | { 64 | return edge_list; 65 | } 66 | 67 | void add_edge(Edge&& e) 68 | { 69 | // Check if the source and destination vertices are within range 70 | if (e.src >= 1 && e.src <= V && 71 | e.dest >= 1 && e.dest <= V) 72 | edge_list.emplace_back(e); 73 | else 74 | std::cerr << "Vertex out of bounds" << std::endl; 75 | } 76 | 77 | // Returns all outgoing edges from vertex v 78 | auto outgoing_edges(size_t v) const 79 | { 80 | std::vector> edges_from_v; 81 | for (auto& e : edge_list) 82 | { 83 | if (e.src == v) 84 | edges_from_v.emplace_back(e); 85 | } 86 | return edges_from_v; 87 | } 88 | 89 | // Overloads the << operator so a graph be written directly to a stream 90 | // Can be used as std::cout << obj << std::endl; 91 | friend std::ostream& operator<< <>(std::ostream& os, const Graph& G); 92 | 93 | private: 94 | size_t V; // Stores number of vertices in graph 95 | std::vector> edge_list; 96 | }; 97 | 98 | template 99 | auto create_bipartite_reference_graph() 100 | { 101 | Graph G(10); 102 | 103 | std::map>> edges; 104 | edges[1] = { {2, 0} }; 105 | edges[2] = { {1, 0}, {3, 0} , {8, 0} }; 106 | edges[3] = { {2, 0}, {4, 0} }; 107 | edges[4] = { {3, 0}, {6, 0} }; 108 | edges[5] = { {7, 0}, {9, 0} }; 109 | edges[6] = { {1, 0}, {4, 0} }; 110 | edges[7] = { {5, 0} }; 111 | edges[8] = { {2,0}, {9, 0} }; 112 | edges[9] = { {5, 0} }; 113 | 114 | 115 | for (auto& i : edges) 116 | for (auto& j : i.second) 117 | G.add_edge(Edge{ i.first, j.first, j.second }); 118 | 119 | return G; 120 | } 121 | 122 | template 123 | auto bipartite_check(const Graph& G) 124 | { 125 | std::stack stack; 126 | std::set visited; 127 | stack.push(1); // Assume that BFS always starts from vertex ID 1 128 | 129 | enum class colors {NONE, RED, BLUE}; 130 | colors current_color{colors::BLUE}; // This variable tracks the color to be assigned to the 131 | // next vertex that is visited. 132 | std::vector vertex_colors(G.vertices(), colors::NONE); 133 | 134 | while (!stack.empty()) 135 | { 136 | auto current_vertex = stack.top(); 137 | stack.pop(); 138 | 139 | // If the current vertex hasn't been visited in the past 140 | if (visited.find(current_vertex) == visited.end()) 141 | { 142 | visited.insert(current_vertex); 143 | vertex_colors[current_vertex] = current_color; 144 | if (current_color == colors::RED) 145 | { 146 | std::cout << "Coloring vertex " << current_vertex << " RED" << std::endl; 147 | current_color = colors::BLUE; 148 | } 149 | else 150 | { 151 | std::cout << "Coloring vertex " << current_vertex << " BLUE" << std::endl; 152 | current_color = colors::RED; 153 | } 154 | 155 | // Add unvisited adjacent vertices to the stack. 156 | for (auto e : G.outgoing_edges(current_vertex)) 157 | if (visited.find(e.dest) == visited.end()) 158 | stack.push(e.dest); 159 | } 160 | // If the found vertex is already colored and 161 | // has a color same as its parent's color, the graph is not bipartite 162 | else if (visited.find(current_vertex) != visited.end() && 163 | ((vertex_colors[current_vertex] == colors::BLUE && 164 | current_color == colors::RED) || 165 | (vertex_colors[current_vertex] == colors::RED && 166 | current_color == colors::BLUE))) 167 | return false; 168 | } 169 | 170 | // If all vertices have been colored, the graph is bipartite 171 | return true; 172 | } 173 | 174 | template 175 | void test_bipartite() 176 | { 177 | // Create an instance of and print the graph 178 | auto BG = create_bipartite_reference_graph(); 179 | std::cout << BG << std::endl; 180 | 181 | if (bipartite_check(BG)) 182 | std::cout << "The graph is bipartite" << std::endl; 183 | else 184 | std::cout << "The graph is not bipartite" << std::endl; 185 | } 186 | 187 | int main() 188 | { 189 | using T = unsigned; 190 | test_bipartite(); 191 | 192 | return 0; 193 | } 194 | 195 | -------------------------------------------------------------------------------- /Lesson6/Exercise28/bfs.cpp: -------------------------------------------------------------------------------- 1 | // Chapter6.cpp : Defines the entry point for the application. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // BFS 10 | #include 11 | 12 | template class Graph; 13 | 14 | template 15 | struct Edge 16 | { 17 | size_t src; 18 | size_t dest; 19 | T weight; 20 | 21 | // To compare edges, only compare their weights, 22 | // and not the source/destination vertices 23 | inline bool operator< (const Edge& e) const 24 | { 25 | return this->weight < e.weight; 26 | } 27 | 28 | inline bool operator> (const Edge& e) const 29 | { 30 | return this->weight > e.weight; 31 | } 32 | }; 33 | 34 | template 35 | std::ostream& operator<<(std::ostream& os, const Graph& G) 36 | { 37 | for (auto i = 1; i < G.vertices(); i++) 38 | { 39 | os << i << ":\t"; 40 | 41 | auto edges = G.outgoing_edges(i); 42 | for (auto& e : edges) 43 | os << "{" << e.dest << ": " << e.weight << "}, "; 44 | 45 | os << std::endl; 46 | } 47 | 48 | return os; 49 | } 50 | 51 | template 52 | class Graph 53 | { 54 | public: 55 | // Initialize the graph with N vertices 56 | Graph(size_t N) : V(N) 57 | {} 58 | 59 | // Return number of vertices in the graph 60 | auto vertices() const 61 | { 62 | return V; 63 | } 64 | 65 | // Return all edges in the graph 66 | auto& edges() const 67 | { 68 | return edge_list; 69 | } 70 | 71 | void add_edge(Edge&& e) 72 | { 73 | // Check if the source and destination vertices are within range 74 | if (e.src >= 1 && e.src <= V && 75 | e.dest >= 1 && e.dest <= V) 76 | edge_list.emplace_back(e); 77 | else 78 | std::cerr << "Vertex out of bounds" << std::endl; 79 | } 80 | 81 | // Returns all outgoing edges from vertex v 82 | auto outgoing_edges(size_t v) const 83 | { 84 | std::vector> edges_from_v; 85 | for (auto& e : edge_list) 86 | { 87 | if (e.src == v) 88 | edges_from_v.emplace_back(e); 89 | } 90 | return edges_from_v; 91 | } 92 | 93 | // Overloads the << operator so a graph be written directly to a stream 94 | // Can be used as std::cout << obj << std::endl; 95 | friend std::ostream& operator<< <>(std::ostream& os, const Graph& G); 96 | 97 | private: 98 | size_t V; // Stores number of vertices in graph 99 | std::vector> edge_list; 100 | }; 101 | 102 | template 103 | auto create_reference_graph() 104 | { 105 | Graph G(9); 106 | 107 | std::map>> edges; 108 | edges[1] = { {2, 2}, {5, 3} }; 109 | edges[2] = { {1, 2}, {5, 5}, {4, 1} }; 110 | edges[3] = { {4, 2}, {7, 3} }; 111 | edges[4] = { {2, 1}, {3, 2}, {5, 2}, {6, 4}, {8, 5} }; 112 | edges[5] = { {1, 3}, {2, 5}, {4, 2}, {8, 3} }; 113 | edges[6] = { {4, 4}, {7, 4}, {8, 1} }; 114 | edges[7] = { {3, 3}, {6, 4} }; 115 | edges[8] = { {4, 5}, {5, 3}, {6, 1} }; 116 | 117 | for (auto& i : edges) 118 | for (auto& j : i.second) 119 | G.add_edge(Edge{ i.first, j.first, j.second }); 120 | 121 | return G; 122 | } 123 | 124 | 125 | template 126 | auto breadth_first_search(const Graph& G, size_t dest) 127 | { 128 | std::queue queue; 129 | std::vector visit_order; 130 | std::set visited; 131 | queue.push(1); // Assume that BFS always starts from vertex ID 1 132 | 133 | while (!queue.empty()) 134 | { 135 | auto current_vertex = queue.front(); 136 | queue.pop(); 137 | 138 | // If the current vertex hasn't been visited in the past 139 | if (visited.find(current_vertex) == visited.end()) 140 | { 141 | visited.insert(current_vertex); 142 | visit_order.push_back(current_vertex); 143 | 144 | for (auto e : G.outgoing_edges(current_vertex)) 145 | queue.push(e.dest); 146 | } 147 | } 148 | 149 | return visit_order; 150 | } 151 | 152 | template 153 | void test_BFS() 154 | { 155 | // Create an instance of and print the graph 156 | auto G = create_reference_graph(); 157 | std::cout << G << std::endl; 158 | 159 | // Run BFS starting from vertex ID 1 and print the order 160 | // in which vertices are visited. 161 | std::cout << "BFS Order of vertices: " << std::endl; 162 | auto bfs_visit_order = breadth_first_search(G, 1); 163 | for (auto v : bfs_visit_order) 164 | std::cout << v << std::endl; 165 | } 166 | 167 | int main() 168 | { 169 | using T = unsigned; 170 | test_BFS(); 171 | 172 | return 0; 173 | } 174 | -------------------------------------------------------------------------------- /Lesson6/Exercise29/dfs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template class Graph; 9 | 10 | template 11 | struct Edge 12 | { 13 | size_t src; 14 | size_t dest; 15 | T weight; 16 | 17 | // To compare edges, only compare their weights, 18 | // and not the source/destination vertices 19 | inline bool operator< (const Edge& e) const 20 | { 21 | return this->weight < e.weight; 22 | } 23 | 24 | inline bool operator> (const Edge& e) const 25 | { 26 | return this->weight > e.weight; 27 | } 28 | }; 29 | 30 | template 31 | std::ostream& operator<<(std::ostream& os, const Graph& G) 32 | { 33 | for (auto i = 1; i < G.vertices(); i++) 34 | { 35 | os << i << ":\t"; 36 | 37 | auto edges = G.outgoing_edges(i); 38 | for (auto& e : edges) 39 | os << "{" << e.dest << ": " << e.weight << "}, "; 40 | 41 | os << std::endl; 42 | } 43 | 44 | return os; 45 | } 46 | 47 | template 48 | class Graph 49 | { 50 | public: 51 | // Initialize the graph with N vertices 52 | Graph(size_t N) : V(N) 53 | {} 54 | 55 | // Return number of vertices in the graph 56 | auto vertices() const 57 | { 58 | return V; 59 | } 60 | 61 | // Return all edges in the graph 62 | auto& edges() const 63 | { 64 | return edge_list; 65 | } 66 | 67 | void add_edge(Edge&& e) 68 | { 69 | // Check if the source and destination vertices are within range 70 | if (e.src >= 1 && e.src <= V && 71 | e.dest >= 1 && e.dest <= V) 72 | edge_list.emplace_back(e); 73 | else 74 | std::cerr << "Vertex out of bounds" << std::endl; 75 | } 76 | 77 | // Returns all outgoing edges from vertex v 78 | auto outgoing_edges(size_t v) const 79 | { 80 | std::vector> edges_from_v; 81 | for (auto& e : edge_list) 82 | { 83 | if (e.src == v) 84 | edges_from_v.emplace_back(e); 85 | } 86 | return edges_from_v; 87 | } 88 | 89 | // Overloads the << operator so a graph be written directly to a stream 90 | // Can be used as std::cout << obj << std::endl; 91 | friend std::ostream& operator<< <>(std::ostream& os, const Graph& G); 92 | 93 | private: 94 | size_t V; // Stores number of vertices in graph 95 | std::vector> edge_list; 96 | }; 97 | 98 | template 99 | auto create_reference_graph() 100 | { 101 | Graph G(9); 102 | 103 | std::map>> edges; 104 | edges[1] = { {2, 0}, {5, 0} }; 105 | edges[2] = { {1, 0}, {5, 0}, {4, 0} }; 106 | edges[3] = { {4, 0}, {7, 0} }; 107 | edges[4] = { {2, 0}, {3, 0}, {5, 0}, {6, 0}, {8, 0} }; 108 | edges[5] = { {1, 0}, {2, 0}, {4, 0}, {8, 0} }; 109 | edges[6] = { {4, 0}, {7, 0}, {8, 0} }; 110 | edges[7] = { {3, 0}, {6, 0} }; 111 | edges[8] = { {4, 0}, {5, 0}, {6, 0} }; 112 | 113 | for (auto& i : edges) 114 | for (auto& j : i.second) 115 | G.add_edge(Edge{ i.first, j.first, j.second }); 116 | 117 | return G; 118 | } 119 | 120 | template 121 | auto depth_first_search(const Graph& G, size_t dest) 122 | { 123 | std::stack stack; 124 | std::vector visit_order; 125 | std::set visited; 126 | stack.push(1); // Assume that DFS always starts from vertex ID 1 127 | 128 | while (!stack.empty()) 129 | { 130 | auto current_vertex = stack.top(); 131 | stack.pop(); 132 | 133 | // If the current vertex hasn't been visited in the past 134 | if (visited.find(current_vertex) == visited.end()) 135 | { 136 | visited.insert(current_vertex); 137 | visit_order.push_back(current_vertex); 138 | 139 | for (auto e : G.outgoing_edges(current_vertex)) 140 | { 141 | // If the vertex hasn't been visited, insert it in the stack. 142 | if (visited.find(e.dest) == visited.end()) 143 | { 144 | stack.push(e.dest); 145 | } 146 | } 147 | } 148 | } 149 | 150 | return visit_order; 151 | } 152 | 153 | template 154 | void test_DFS() 155 | { 156 | // Create an instance of and print the graph 157 | auto G = create_reference_graph(); 158 | std::cout << G << std::endl; 159 | 160 | // Run DFS starting from vertex ID 1 and print the order 161 | // in which vertices are visited. 162 | std::cout << "DFS Order of vertices: " << std::endl; 163 | auto dfs_visit_order = depth_first_search(G, 1); 164 | for (auto v : dfs_visit_order) 165 | std::cout << v << std::endl; 166 | } 167 | 168 | int main() 169 | { 170 | using T = unsigned; 171 | test_DFS(); 172 | 173 | return 0; 174 | } -------------------------------------------------------------------------------- /Lesson6/Exercise30/prim.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | template class Graph; 10 | 11 | template 12 | struct Edge 13 | { 14 | size_t src; 15 | size_t dest; 16 | T weight; 17 | 18 | // To compare edges, only compare their weights, 19 | // and not the source/destination vertices 20 | inline bool operator< (const Edge& e) const 21 | { 22 | return this->weight < e.weight; 23 | } 24 | 25 | inline bool operator> (const Edge& e) const 26 | { 27 | return this->weight > e.weight; 28 | } 29 | }; 30 | 31 | template 32 | std::ostream& operator<<(std::ostream& os, const Graph& G) 33 | { 34 | for (auto i = 1; i < G.vertices(); i++) 35 | { 36 | os << i << ":\t"; 37 | 38 | auto edges = G.outgoing_edges(i); 39 | for (auto& e : edges) 40 | os << "{" << e.dest << ": " << e.weight << "}, "; 41 | 42 | os << std::endl; 43 | } 44 | 45 | return os; 46 | } 47 | 48 | template 49 | class Graph 50 | { 51 | public: 52 | // Initialize the graph with N vertices 53 | Graph(size_t N) : V(N) 54 | {} 55 | 56 | // Return number of vertices in the graph 57 | auto vertices() const 58 | { 59 | return V; 60 | } 61 | 62 | // Return all edges in the graph 63 | auto& edges() const 64 | { 65 | return edge_list; 66 | } 67 | 68 | void add_edge(Edge&& e) 69 | { 70 | // Check if the source and destination vertices are within range 71 | if (e.src >= 1 && e.src <= V && 72 | e.dest >= 1 && e.dest <= V) 73 | edge_list.emplace_back(e); 74 | else 75 | std::cerr << "Vertex out of bounds" << std::endl; 76 | } 77 | 78 | // Returns all outgoing edges from vertex v 79 | auto outgoing_edges(size_t v) const 80 | { 81 | std::vector> edges_from_v; 82 | for (auto& e : edge_list) 83 | { 84 | if (e.src == v) 85 | edges_from_v.emplace_back(e); 86 | } 87 | return edges_from_v; 88 | } 89 | 90 | // Overloads the << operator so a graph be written directly to a stream 91 | // Can be used as std::cout << obj << std::endl; 92 | friend std::ostream& operator<< <>(std::ostream& os, const Graph& G); 93 | 94 | private: 95 | size_t V; // Stores number of vertices in graph 96 | std::vector> edge_list; 97 | }; 98 | 99 | template 100 | auto create_reference_graph() 101 | { 102 | Graph G(9); 103 | 104 | std::map>> edges; 105 | edges[1] = { {2, 2}, {5, 3} }; 106 | edges[2] = { {1, 2}, {5, 5}, {4, 1} }; 107 | edges[3] = { {4, 2}, {7, 3} }; 108 | edges[4] = { {2, 1}, {3, 2}, {5, 2}, {6, 4}, {8, 5} }; 109 | edges[5] = { {1, 3}, {2, 5}, {4, 2}, {8, 3} }; 110 | edges[6] = { {4, 4}, {7, 4}, {8, 1} }; 111 | edges[7] = { {3, 3}, {6, 4} }; 112 | edges[8] = { {4, 5}, {5, 3}, {6, 1} }; 113 | 114 | for (auto& i : edges) 115 | for (auto& j : i.second) 116 | G.add_edge(Edge{ i.first, j.first, j.second }); 117 | 118 | return G; 119 | } 120 | 121 | template 122 | struct Label 123 | { 124 | size_t vertex_ID; 125 | T distance_from_frontier; 126 | 127 | Label(size_t _id, T _distance) : 128 | vertex_ID(_id), 129 | distance_from_frontier(_distance) 130 | {} 131 | 132 | // To compare labels, only compare their distances from source 133 | inline bool operator< (const Label& l) const 134 | { 135 | return this->distance_from_frontier < l.distance_from_frontier; 136 | } 137 | 138 | inline bool operator> (const Label& l) const 139 | { 140 | return this->distance_from_frontier > l.distance_from_frontier; 141 | } 142 | 143 | inline bool operator() (const Label& l) const 144 | { 145 | return this > l; 146 | } 147 | }; 148 | 149 | template 150 | auto prim_MST(const Graph& G, size_t src) 151 | { 152 | std::priority_queue, std::vector>, std::greater>> heap; 153 | std::set visited; 154 | 155 | std::vector distance(G.vertices(), std::numeric_limits::max()); 156 | std::vector MST; 157 | 158 | heap.emplace(src, 0); 159 | 160 | // Search for the destination vertex in the graph 161 | while (!heap.empty()) 162 | { 163 | auto current_vertex = heap.top(); 164 | heap.pop(); 165 | 166 | // If the current vertex hasn't been visited in the past 167 | if (visited.find(current_vertex.vertex_ID) == visited.end()) 168 | { 169 | MST.push_back(current_vertex.vertex_ID); 170 | 171 | // For each outgoing edge from the current vertex, 172 | // create a label for the destination vertex and add it to the heap 173 | for (auto e : G.outgoing_edges(current_vertex.vertex_ID)) 174 | { 175 | auto neighbor_vertex_ID = e.dest; 176 | auto new_distance_to_frontier = e.weight; 177 | 178 | // Check if the new path to the vertex is shorter 179 | // than the previously known best path. If yes, update the distance 180 | if (new_distance_to_frontier < distance[neighbor_vertex_ID]) 181 | { 182 | heap.emplace(neighbor_vertex_ID, new_distance_to_frontier); 183 | distance[e.dest] = new_distance_to_frontier; 184 | } 185 | } 186 | 187 | visited.insert(current_vertex.vertex_ID); 188 | } 189 | } 190 | 191 | return MST; 192 | } 193 | 194 | template 195 | void test_prim_MST() 196 | { 197 | auto G = create_reference_graph(); 198 | std::cout << G << std::endl; 199 | 200 | auto MST = prim_MST(G, 1); 201 | 202 | std::cout << "Minimum Spanning Tree:" << std::endl; 203 | for (auto v : MST) 204 | std::cout << v << std::endl; 205 | std::cout << std::endl; 206 | } 207 | 208 | int main() 209 | { 210 | using T = unsigned; 211 | test_prim_MST(); 212 | 213 | return 0; 214 | } -------------------------------------------------------------------------------- /Lesson7/Activity15/Activity 15.cpp: -------------------------------------------------------------------------------- 1 | // Chapter 7 : Activity 1 (Greedy Robot) 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | struct Edge 10 | { 11 | int start; 12 | int end; 13 | int weight; 14 | 15 | Edge() {} 16 | Edge(int u, int v, int w) : start(u), end(v), weight(w) {} 17 | }; 18 | 19 | const int UNKNOWN = INT_MAX; 20 | 21 | int BellmanFord(int N, vector edges) 22 | { 23 | vector distance(N + 1, UNKNOWN); 24 | 25 | // Starting node is always index 00 26 | distance[0] = 0; 27 | 28 | for(int i = 0; i < N - 1; i++) 29 | { 30 | for(auto edge : edges) 31 | { 32 | if(distance[edge->start] == UNKNOWN) 33 | { 34 | continue; 35 | } 36 | 37 | if(distance[edge->start] + edge->weight < distance[edge->end]) 38 | { 39 | distance[edge->end] = distance[edge->start] + edge->weight; 40 | } 41 | } 42 | } 43 | // Check for negative cycles 44 | for(auto edge : edges) 45 | { 46 | if(distance[edge->start] == UNKNOWN) 47 | { 48 | continue; 49 | } 50 | if(distance[edge->start] + edge->weight < distance[edge->end]) 51 | { 52 | return UNKNOWN; 53 | } 54 | } 55 | return distance[N-1]; 56 | } 57 | 58 | 59 | int main() 60 | { 61 | int N; 62 | cin >> N; 63 | 64 | vector edges; 65 | 66 | for(int i = 0; i < N * N - 1; i++) 67 | { 68 | string directions; 69 | int power; 70 | 71 | cin >> directions >> power; 72 | 73 | for(auto d : directions) 74 | { 75 | int next; 76 | 77 | switch(d) 78 | { 79 | case 'N': next = i - N; break; 80 | case 'E': next = i + 1; break; 81 | case 'S': next = i + N; break; 82 | case 'W': next = i - 1; break; 83 | } 84 | // Add edge with power variable's sign reversed 85 | edges.push_back(new Edge(i, next, -power)); 86 | } 87 | } 88 | int result = BellmanFord(N * N, edges); 89 | 90 | (result == UNKNOWN) ? cout << "TRAVERSAL ABORTED" << endl 91 | : cout << -1 * result << endl; 92 | 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /Lesson7/Activity16/Activity 16.cpp: -------------------------------------------------------------------------------- 1 | // Activity 7-2 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | const int UNKNOWN = 1e9; 11 | 12 | static unsigned long int next_random = 1; 13 | 14 | int rand(void) 15 | { 16 | next_random = next_random * 1103515245 + 12345; 17 | return (unsigned int)(next_random / 65536) % 32768; 18 | } 19 | 20 | void srand(unsigned int seed) 21 | { 22 | next_random = seed; 23 | } 24 | 25 | enum RESULT 26 | { 27 | VALID, 28 | INVALID, 29 | INTERESTING 30 | }; 31 | 32 | struct Edge 33 | { 34 | int u; 35 | int v; 36 | int w; 37 | 38 | Edge(){} 39 | Edge(int u, int v, int w) 40 | : u(u), v(v), w(w) {} 41 | }; 42 | 43 | struct Graph 44 | { 45 | int V, E; 46 | int maxWeight = -1e9; 47 | 48 | vector edges; 49 | vector> adj; 50 | vector> weight; 51 | 52 | Graph(int v, int e) : V(v), E(e) 53 | { 54 | vector> used(V, vector(V, false)); 55 | 56 | adj.resize(V); 57 | weight.resize(V, vector(V, UNKNOWN)); 58 | 59 | while (e) 60 | { 61 | // Generate edge values 62 | int u = rand() % V; 63 | int v = rand() % V; 64 | int w = rand() % 100; 65 | 66 | if (rand() % 3 == 0) 67 | { 68 | w = -w; 69 | } 70 | 71 | // Check if the edge is valid 72 | if (u == v || used[u][v]) 73 | { 74 | continue; 75 | } 76 | 77 | // Add to edges and mark as used 78 | edges.push_back(Edge(u, v, w)); 79 | adj[u].push_back(v); 80 | weight[u][v] = w; 81 | maxWeight = max(maxWeight, w); 82 | 83 | used[u][u] = used[v][v] = used[u][v] = used[v][u] = true; 84 | e--; 85 | } 86 | for (int i = 0; i < V; i++) 87 | { 88 | // Set V to -1 to indicate the graph is invalid 89 | if (!used[i][i]) 90 | { 91 | V = -1; 92 | break; 93 | } 94 | } 95 | } 96 | }; 97 | 98 | vector BellmanFord(Graph G) 99 | { 100 | vector distance(G.V + 1, UNKNOWN); 101 | 102 | int s = G.V; 103 | 104 | for (int i = 0; i < G.V; i++) 105 | { 106 | G.edges.push_back(Edge(s, i, 0)); 107 | } 108 | distance[s] = 0; 109 | 110 | for (int i = 0; i < G.V; i++) 111 | { 112 | for (auto edge : G.edges) 113 | { 114 | if (distance[edge.u] == UNKNOWN) 115 | { 116 | continue; 117 | } 118 | 119 | if (distance[edge.u] + edge.w < distance[edge.v]) 120 | { 121 | distance[edge.v] = distance[edge.u] + edge.w; 122 | } 123 | } 124 | } 125 | 126 | for (auto edge : G.edges) 127 | { 128 | if (distance[edge.u] == UNKNOWN) 129 | { 130 | continue; 131 | } 132 | 133 | if (distance[edge.u] + edge.w < distance[edge.v]) 134 | { 135 | return {}; 136 | } 137 | } 138 | return distance; 139 | } 140 | 141 | vector Dijkstra(int source, Graph G) 142 | { 143 | typedef pair State; 144 | 145 | priority_queue, greater> Q; 146 | vector visited(G.V, false); 147 | vector distance(G.V, UNKNOWN); 148 | 149 | Q.push({ 0, source }); 150 | distance[source] = 0; 151 | 152 | while (!Q.empty()) 153 | { 154 | State top = Q.top(); 155 | Q.pop(); 156 | 157 | int node = top.second; 158 | int dist = top.first; 159 | 160 | visited[node] = true; 161 | 162 | for (auto next : G.adj[node]) 163 | { 164 | if (visited[next]) 165 | { 166 | continue; 167 | } 168 | if (dist != UNKNOWN && distance[next] > dist + G.weight[node][next]) 169 | { 170 | distance[next] = dist + G.weight[node][next]; 171 | 172 | Q.push({ distance[next], next }); 173 | } 174 | } 175 | } 176 | return distance; 177 | } 178 | 179 | RESULT TestGraph(Graph G) 180 | { 181 | if (G.V == -1) 182 | { 183 | return INVALID; 184 | } 185 | 186 | vector distance = BellmanFord(G); 187 | 188 | if (distance.empty()) 189 | { 190 | return VALID; 191 | } 192 | 193 | for (auto edge : G.edges) 194 | { 195 | G.weight[edge.u][edge.v] += (distance[edge.u] - distance[edge.v]); 196 | } 197 | 198 | double result = 0; 199 | 200 | for (int i = 0; i < G.V; i++) 201 | { 202 | vector shortest = Dijkstra(i, G); 203 | 204 | double average = 0; 205 | int count = 0; 206 | 207 | for (int j = 0; j < G.V; j++) 208 | { 209 | if (i == j || shortest[j] == UNKNOWN) 210 | { 211 | continue; 212 | } 213 | shortest[j] += (distance[j] - distance[i]); 214 | average += shortest[j]; 215 | count++; 216 | } 217 | 218 | average = average / count; 219 | result += average; 220 | } 221 | result = result / G.V; 222 | 223 | double ratio = result / G.maxWeight; 224 | 225 | return (ratio < 0.5) ? INTERESTING : VALID; 226 | } 227 | 228 | int main() 229 | { 230 | long seed; 231 | int iterations, V, E; 232 | 233 | cin >> seed; 234 | cin >> iterations; 235 | cin >> V >> E; 236 | 237 | int invalid = 0; 238 | int valid = 0; 239 | int interesting = 0; 240 | 241 | srand(seed); 242 | 243 | while (iterations--) 244 | { 245 | Graph G(V, E); 246 | 247 | switch (TestGraph(G)) 248 | { 249 | case INVALID: invalid++; break; 250 | case VALID: valid++; break; 251 | case INTERESTING: 252 | { 253 | valid++; 254 | interesting++; 255 | break; 256 | } 257 | } 258 | } 259 | double percentInteresting = (double)interesting / valid * 100; 260 | 261 | cout << "INVALID: " << invalid << endl; 262 | cout << "PERCENT INTERESTING: " << fixed << setprecision(2) << percentInteresting << "%" << endl; 263 | 264 | return 0; 265 | } 266 | -------------------------------------------------------------------------------- /Lesson7/Activity17/Activity 17.cpp: -------------------------------------------------------------------------------- 1 | // Chapter 7 : Activity 3 (Maze Teleportation Game) 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | struct Edge 11 | { 12 | int start; 13 | int end; 14 | int weight; 15 | 16 | Edge(int s, int e, int w) : start(s), end(e), weight(w) {} 17 | }; 18 | 19 | const int UNKNOWN = INT_MAX; 20 | 21 | void FillStack(int node, vector> &adj, vector &visited, vector &stack) 22 | { 23 | visited[node] = true; 24 | 25 | for(auto next : adj[node]) 26 | { 27 | if(!visited[next]) 28 | { 29 | FillStack(next, adj, visited, stack); 30 | } 31 | } 32 | stack.push_back(node); 33 | } 34 | 35 | vector isStuck; 36 | vector inComponent; 37 | int componentIndex; 38 | 39 | void GetComponent(int node, vector> &adj, vector &visited, vector &component) 40 | { 41 | component.push_back(node); 42 | visited[node] = true; 43 | 44 | inComponent[node] = componentIndex; 45 | 46 | for(auto next : adj[node]) 47 | { 48 | if(!visited[next]) 49 | { 50 | GetComponent(next, adj, visited, component); 51 | } 52 | else if(inComponent[node] != inComponent[next]) 53 | { 54 | isStuck[inComponent[next]] = false; 55 | } 56 | } 57 | } 58 | 59 | vector> GetTranspose(int V, vector> adj) 60 | { 61 | vector> transpose(V); 62 | 63 | for(int i = 0; i < V; i++) 64 | { 65 | for(auto next : adj[i]) 66 | { 67 | transpose[next].push_back(i); 68 | } 69 | } 70 | return transpose; 71 | } 72 | 73 | vector> Kosaraju(int V, vector> adj) 74 | { 75 | isStuck.resize(V, true); 76 | inComponent.resize(V, UNKNOWN); 77 | componentIndex = 0; 78 | 79 | vector visited(V, false); 80 | vector stack; 81 | 82 | for(int i = 0; i < V; i++) 83 | { 84 | if(!visited[i]) 85 | { 86 | FillStack(i, adj, visited, stack); 87 | } 88 | } 89 | vector> transpose = GetTranspose(V, adj); 90 | vector> components; 91 | 92 | fill(visited.begin(), visited.end(), false); 93 | 94 | while(!stack.empty()) 95 | { 96 | int node = stack.back(); 97 | stack.pop_back(); 98 | 99 | if(!visited[node]) 100 | { 101 | vector component; 102 | 103 | GetComponent(node, transpose, visited, component); 104 | 105 | components.push_back(component); 106 | componentIndex++; 107 | } 108 | } 109 | return components; 110 | } 111 | 112 | bool HasNegativeCycle(vector distance, vector edges) 113 | { 114 | // Iterate through edges one last time 115 | for(auto edge : edges) 116 | { 117 | int u = edge->start; 118 | int v = edge->end; 119 | int w = edge->weight; 120 | 121 | if(distance[u] == UNKNOWN) continue; 122 | 123 | // If we can still find any path shorter than one we have already found, the graph must contain 124 | // a negative cycle. 125 | 126 | if(distance[u] + w < distance[v]) 127 | { 128 | return true; 129 | } 130 | } 131 | return false; 132 | } 133 | 134 | int BellmanFord(int V, int start, vector edges) 135 | { 136 | // Standard Bellman-Ford implementation 137 | 138 | vector distance(V, UNKNOWN); 139 | 140 | distance[start] = 0; 141 | 142 | for(int i = 0; i < V - 1; i++) 143 | { 144 | for(auto edge : edges) 145 | { 146 | if(distance[edge->start] == UNKNOWN) 147 | { 148 | continue; 149 | } 150 | 151 | if(distance[edge->start] + edge->weight < distance[edge->end]) 152 | { 153 | distance[edge->end] = distance[edge->start] + edge->weight; 154 | } 155 | } 156 | } 157 | if(HasNegativeCycle(distance, edges)) 158 | { 159 | return UNKNOWN; 160 | } 161 | 162 | int result = UNKNOWN; 163 | 164 | for(int i = 0; i < V; i++) 165 | { 166 | if(i == start) continue; 167 | 168 | result = min(result, distance[i]); 169 | } 170 | return result; 171 | } 172 | 173 | 174 | int main() 175 | { 176 | int V, E; 177 | cin >> V >> E; 178 | 179 | vector edges; 180 | vector> adj(V + 1); 181 | 182 | for(int i = 0; i < E; i++) 183 | { 184 | int u, v, w; 185 | cin >> u >> v >> w; 186 | 187 | edges.push_back(new Edge(u, v, w)); 188 | adj[u].push_back(v); 189 | } 190 | 191 | vector results; 192 | 193 | for(int i = 0; i < V; i++) 194 | { 195 | if(adj[i].empty()) 196 | { 197 | results.push_back(UNKNOWN); 198 | continue; 199 | } 200 | int shortest = BellmanFord(V, i, edges); 201 | 202 | if(shortest == UNKNOWN) 203 | { 204 | cout << "INVALID MAZE" << endl; 205 | return 0; 206 | } 207 | results.push_back(shortest); 208 | } 209 | for(int i = 0; i < V; i++) 210 | { 211 | cout << i << ": "; 212 | 213 | (results[i] == UNKNOWN) ? cout << "DEAD END" << endl 214 | : cout << results[i] << endl; 215 | } 216 | auto components = Kosaraju(V, adj); 217 | 218 | for(int i = 0; i < components.size(); i++) 219 | { 220 | if(isStuck[i]) 221 | { 222 | for(auto node : components[i]) 223 | { 224 | cout << node << " "; 225 | } 226 | cout << endl; 227 | } 228 | } 229 | return 0; 230 | } 231 | 232 | -------------------------------------------------------------------------------- /Lesson7/Exercise32/Exercise32.cpp: -------------------------------------------------------------------------------- 1 | // Exercise 32 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | struct Edge 10 | { 11 | int start; // The starting vertex 12 | int end; // The destination vertex 13 | int weight; // The edge weight 14 | 15 | // Constructor 16 | Edge(int s, int e, int w) : start(s), end(e), weight(w) {} 17 | }; 18 | 19 | const int UNKNOWN = INT_MAX; 20 | 21 | vector edges; // Collection of edge pointers 22 | int V; // Total number of vertices in graph 23 | int E; // Total number of edges in graph 24 | 25 | void BellmanFord(int start) 26 | { 27 | vector distance(V, UNKNOWN); 28 | 29 | distance[start] = 0; 30 | 31 | // Perform V - 1 iterations 32 | for(int i = 0; i < V; i++) 33 | { 34 | // Iterate over entire set of edges 35 | for(auto edge : edges) 36 | { 37 | int u = edge->start; 38 | int v = edge->end; 39 | int w = edge->weight; 40 | 41 | // Skip nodes which have not yet been considered 42 | if(distance[u] == UNKNOWN) 43 | { 44 | continue; 45 | } 46 | 47 | // If the current distance value for the destination 48 | // node is greater than the sum of the source node's 49 | // distance and the edge's weight, change its distance 50 | // to the lesser value 51 | 52 | if(distance[u] + w < distance[v]) 53 | { 54 | distance[v] = distance[u] + w; 55 | } 56 | } 57 | } 58 | 59 | cout << "DISTANCE FROM VERTEX " << start << ":\n"; 60 | 61 | for(int i = 0; i < V; i++) 62 | { 63 | cout << "\t" << i << ": "; 64 | 65 | if(distance[i] == UNKNOWN) 66 | { 67 | cout << "Unvisited" << endl; 68 | continue; 69 | } 70 | cout << distance[i] << endl; 71 | } 72 | } 73 | 74 | int main() 75 | { 76 | cin >> V >> E; 77 | 78 | for(int i = 0; i < E; i++) 79 | { 80 | int node_a, node_b, weight; 81 | cin >> node_a >> node_b >> weight; 82 | 83 | // Add a new edge using the defined constructor 84 | edges.push_back(new Edge(node_a, node_b, weight)); 85 | } 86 | 87 | // Choose a starting node 88 | 89 | int start; 90 | cin >> start; 91 | 92 | // Run the Bellman-Ford algorithm on the graph for 93 | // the chosen starting vertex 94 | 95 | BellmanFord(start); 96 | 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /Lesson7/Exercise33/Exercise33.cpp: -------------------------------------------------------------------------------- 1 | // Exercise 33 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | struct Edge 10 | { 11 | int start; // The starting vertex 12 | int end; // The destination vertex 13 | int weight; // The edge weight 14 | 15 | // Constructor 16 | Edge(int s, int e, int w) : start(s), end(e), weight(w) {} 17 | }; 18 | 19 | const int UNKNOWN = INT_MAX; 20 | 21 | vector edges; // Collection of edge pointers 22 | int V; // Total number of vertices in graph 23 | int E; // Total number of edges in graph 24 | 25 | void BellmanFord(int start) 26 | { 27 | vector distance(V, UNKNOWN); 28 | 29 | distance[start] = 0; 30 | 31 | // Perform V - 1 iterations 32 | for(int i = 0; i < V; i++) 33 | { 34 | // Iterate over entire set of edges 35 | for(auto edge : edges) 36 | { 37 | int u = edge->start; 38 | int v = edge->end; 39 | int w = edge->weight; 40 | 41 | // Skip nodes which have not yet been considered 42 | if(distance[u] == UNKNOWN) 43 | { 44 | continue; 45 | } 46 | 47 | // If the current distance value for the destination 48 | // node is greater than the sum of the source node's 49 | // distance and the edge's weight, change its distance 50 | // to the lesser value 51 | 52 | if(distance[u] + w < distance[v]) 53 | { 54 | distance[v] = distance[u] + w; 55 | } 56 | } 57 | } 58 | for(auto edge : edges) 59 | { 60 | int u = edge->start; 61 | int v = edge->end; 62 | int w = edge->weight; 63 | 64 | if(distance[u] == UNKNOWN) 65 | { 66 | continue; 67 | } 68 | 69 | if(distance[u] + w < distance[v]) 70 | { 71 | cout << "NEGATIVE CYCLE FOUND" << endl; 72 | return; 73 | } 74 | } 75 | 76 | cout << "DISTANCE FROM VERTEX " << start << ":\n"; 77 | 78 | for(int i = 0; i < V; i++) 79 | { 80 | cout << "\t" << i << ": "; 81 | 82 | if(distance[i] == UNKNOWN) 83 | { 84 | cout << "Unvisited" << endl; 85 | continue; 86 | } 87 | cout << distance[i] << endl; 88 | } 89 | } 90 | 91 | int main() 92 | { 93 | cin >> V >> E; 94 | 95 | for(int i = 0; i < E; i++) 96 | { 97 | int node_a, node_b, weight; 98 | cin >> node_a >> node_b >> weight; 99 | 100 | // Add a new edge using the defined constructor 101 | edges.push_back(new Edge(node_a, node_b, weight)); 102 | } 103 | 104 | // Choose a starting node 105 | 106 | int start; 107 | cin >> start; 108 | 109 | // Run the Bellman-Ford algorithm on the graph for 110 | // the chosen starting vertex 111 | 112 | BellmanFord(start); 113 | 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /Lesson7/Exercise34/Exercise34.cpp: -------------------------------------------------------------------------------- 1 | // Exercise 34 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | struct Edge 10 | { 11 | int start; 12 | int end; 13 | int weight; 14 | 15 | Edge(int s, int e, int w) : start(s), end(e), weight(w) {} 16 | }; 17 | 18 | const int UNKNOWN = INT_MAX; 19 | 20 | vector edges; 21 | int V; 22 | int E; 23 | 24 | int GetMinDistance(vector &distance, vector &visited) 25 | { 26 | int minDistance = UNKNOWN; 27 | int result; 28 | 29 | for(int v = 0; v < distance.size(); v++) 30 | { 31 | if(!visited[v] && distance[v] <= minDistance) 32 | { 33 | minDistance = distance[v]; 34 | result = v; 35 | } 36 | } 37 | return result; 38 | } 39 | 40 | vector Dijkstra(int V, int start, vector edges) 41 | { 42 | vector distance(V, UNKNOWN); 43 | vector visited(V, false); 44 | 45 | distance[start] = 0; 46 | 47 | for(int i = 0; i < V - 1; i++) 48 | { 49 | // Find index of unvisited node with shortest distance 50 | int curr = GetMinDistance(distance, visited); 51 | 52 | visited[curr] = true; 53 | 54 | // Iterate through edges 55 | for(auto edge : edges) 56 | { 57 | // Only consider neighboring nodes 58 | if(edge->start != curr) continue; 59 | 60 | // Disregard if already visited 61 | if(visited[edge->end]) continue; 62 | 63 | if(distance[curr] != UNKNOWN && distance[curr] + edge->weight < distance[edge->end]) 64 | { 65 | distance[edge->end] = distance[curr] + edge->weight; 66 | } 67 | } 68 | } 69 | return distance; 70 | } 71 | 72 | bool HasNegativeCycle(vector distance, vector edges) 73 | { 74 | for(auto edge : edges) 75 | { 76 | int u = edge->start; 77 | int v = edge->end; 78 | int w = edge->weight; 79 | 80 | if(distance[u] == UNKNOWN) continue; 81 | 82 | if(distance[u] + w < distance[v]) 83 | { 84 | return true; 85 | } 86 | } 87 | return false; 88 | } 89 | 90 | vector BellmanFord(int V, vector edges) 91 | { 92 | vector distance(V + 1, UNKNOWN); 93 | 94 | int s = V; 95 | 96 | for(int i = 0; i < V; i++) 97 | { 98 | edges.push_back(new Edge(s, i, 0)); 99 | } 100 | 101 | distance[s] = 0; 102 | 103 | for(int i = 1; i < V; i++) 104 | { 105 | for(auto edge : edges) 106 | { 107 | int u = edge->start; 108 | int v = edge->end; 109 | int w = edge->weight; 110 | 111 | if(distance[u] == UNKNOWN) 112 | { 113 | continue; 114 | } 115 | 116 | if(distance[u] + w < distance[v]) 117 | { 118 | distance[v] = distance[u] + w; 119 | } 120 | } 121 | } 122 | 123 | if(HasNegativeCycle(distance, edges)) 124 | { 125 | cout << "NEGATIVE CYCLE FOUND" << endl; 126 | 127 | return {}; 128 | } 129 | 130 | return distance; 131 | } 132 | 133 | void Johnson(int V, vector edges) 134 | { 135 | // Get distance array from modified graph 136 | vector h = BellmanFord(V, edges); 137 | 138 | if(h.empty()) return; 139 | 140 | for(int i = 0; i < edges.size(); i++) 141 | { 142 | edges[i]->weight += (h[edges[i]->start] - h[edges[i]->end]); 143 | } 144 | 145 | // Create a matrix for storing distance values 146 | vector> shortest(V); 147 | 148 | // Retrieve shortest distances for each vertex 149 | for(int i = 0; i < V; i++) 150 | { 151 | shortest[i] = Dijkstra(V, i, edges); 152 | } 153 | 154 | // Reweight again in reverse to get original values 155 | for(int i = 0; i < V; i++) 156 | { 157 | cout << i << ":\n"; 158 | 159 | for(int j = 0; j < V; j++) 160 | { 161 | if(shortest[i][j] != UNKNOWN) 162 | { 163 | shortest[i][j] += h[j] - h[i]; 164 | 165 | cout << "\t" << j << ": " << shortest[i][j] << endl; 166 | } 167 | } 168 | } 169 | } 170 | 171 | int main() 172 | { 173 | int V, E; 174 | cin >> V >> E; 175 | 176 | vector edges; 177 | 178 | for(int i = 0; i < E; i++) 179 | { 180 | int node_a, node_b, weight; 181 | cin >> node_a >> node_b >> weight; 182 | 183 | edges.push_back(new Edge(node_a, node_b, weight)); 184 | } 185 | 186 | Johnson(V, edges); 187 | 188 | return 0; 189 | } 190 | -------------------------------------------------------------------------------- /Lesson7/Exercise35/Exercise35.cpp: -------------------------------------------------------------------------------- 1 | // Exercise 35 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | void FillStack(int node, vector &visited, vector> &adj, stack &stack) 10 | { 11 | visited[node] = true; 12 | 13 | for (auto next : adj[node]) 14 | { 15 | if (!visited[next]) 16 | { 17 | FillStack(next, visited, adj, stack); 18 | } 19 | } 20 | stack.push(node); 21 | } 22 | 23 | void CollectConnectedComponents(int node, vector &visited, vector> &adj, vector &component) 24 | { 25 | visited[node] = true; 26 | component.push_back(node); 27 | 28 | for (auto next : adj[node]) 29 | { 30 | if (!visited[next]) 31 | { 32 | CollectConnectedComponents(next, visited, adj, component); 33 | } 34 | } 35 | } 36 | 37 | vector> Transpose(int V, vector> adj) 38 | { 39 | vector> transpose(V); 40 | 41 | for(int i = 0; i < V; i++) 42 | { 43 | for(auto next : adj[i]) 44 | { 45 | transpose[next].push_back(i); 46 | } 47 | } 48 | return transpose; 49 | } 50 | 51 | vector> Kosaraju(int V, vector> adj) 52 | { 53 | vector visited(V, false); 54 | stack stack; 55 | 56 | for (int i = 0; i < V; i++) 57 | { 58 | if (!visited[i]) 59 | { 60 | FillStack(i, visited, adj, stack); 61 | } 62 | } 63 | vector> transpose = Transpose(V, adj); 64 | 65 | fill(visited.begin(), visited.end(), false); 66 | 67 | vector> connectedComponents; 68 | 69 | while (!stack.empty()) 70 | { 71 | int node = stack.top(); 72 | 73 | stack.pop(); 74 | 75 | if (!visited[node]) 76 | { 77 | vector component; 78 | 79 | CollectConnectedComponents(node, visited, transpose, component); 80 | connectedComponents.push_back(component); 81 | } 82 | } 83 | return connectedComponents; 84 | } 85 | 86 | int main() 87 | { 88 | int V = 9; 89 | 90 | vector> adj = 91 | { 92 | { 1, 3 }, 93 | { 2, 4 }, 94 | { 3, 5 }, 95 | { 7 }, 96 | { 2 }, 97 | { 4, 6 }, 98 | { 7, 2 }, 99 | { 8 }, 100 | { 3 } 101 | }; 102 | 103 | vector> connectedComponents; 104 | connectedComponents = Kosaraju(V, adj); 105 | 106 | cout << "Graph contains " << connectedComponents.size() << " strongly connected components." << endl; 107 | 108 | for (auto component : connectedComponents) 109 | { 110 | cout << "\t"; 111 | 112 | for (auto node : component) 113 | { 114 | cout << node << " "; 115 | } 116 | cout << endl; 117 | } 118 | return 0; 119 | } 120 | -------------------------------------------------------------------------------- /Lesson8/Activity18/Activity 18.cp: -------------------------------------------------------------------------------- 1 | // Chapter 8 : Activity 1 2 | 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | typedef long long LL; 8 | 9 | const LL MOD = 1000000007; 10 | 11 | LL TravelItinerary(int n, vector distance) 12 | { 13 | reverse(distance.begin(), distance.end()); 14 | 15 | vector DP(n + 1, 0); 16 | vector sums(n + 2, 0); 17 | 18 | DP[0] = sums[1] = 1; 19 | 20 | for(int i = 1; i <= n; i++) 21 | { 22 | int dist = distance[i-1]; 23 | LL sum = sums[i] - sums[i - dist]; 24 | 25 | DP[i] = (DP[i] + sum) % MOD; 26 | sums[i + 1] = (sums[i] + DP[i]) % MOD; 27 | } 28 | return (DP[n] < 0) ? DP[n] + MOD : DP[n]; 29 | } 30 | 31 | vector Generate(int n) 32 | { 33 | vector A(n); 34 | 35 | LL val = 1; 36 | 37 | for(int i = 0; i < n; i++) 38 | { 39 | val = (val * 1103515245 + 12345) / 65536; 40 | val %= 32768; 41 | 42 | A[i] = ((val % 10000) % (n - i)) + 1; 43 | } 44 | return A; 45 | } 46 | 47 | int main() 48 | { 49 | int n; 50 | cin >> n; 51 | 52 | vector A(n); 53 | 54 | if(n == 1e7) 55 | { 56 | A = Generate(n); 57 | } 58 | else 59 | { 60 | for(int i = 0; i < n; i++) 61 | { 62 | cin >> A[i]; 63 | } 64 | cout << endl; 65 | } 66 | LL result = TravelItinerary(n, A); 67 | cout << result << "\n"; 68 | 69 | return 0; 70 | } 71 | /* 72 | 3 73 | 1 1 1 74 | = 1 75 | 76 | 6 77 | 1 2 3 2 2 1 78 | = 9 79 | 80 | 15 81 | 1 2 5 3 4 2 1 3 6 1 2 1 2 2 1 82 | = 789 83 | 84 | 40 85 | 8 5 9 9 11 3 10 9 9 5 1 6 13 3 13 9 8 5 11 8 4 5 10 3 11 4 10 4 12 11 8 9 3 7 6 4 4 3 2 1 86 | = 47382972 87 | 88 | 100 89 | 39 79 34 76 12 28 51 60 53 7 30 48 45 61 66 24 50 64 18 47 7 19 16 72 8 55 72 26 43 57 45 26 68 23 52 28 35 54 2 57 29 59 6 57 8 47 6 44 43 35 50 41 45 4 43 39 44 43 42 26 40 39 32 37 31 20 9 33 30 27 30 29 28 27 26 25 24 23 22 15 20 19 18 17 1 15 14 2 12 11 1 6 8 7 6 5 4 3 2 1 90 | = 790903754 91 | 92 | 10000000 93 | = 318948158 94 | */ 95 | -------------------------------------------------------------------------------- /Lesson8/Activity19/Activity 19.cpp: -------------------------------------------------------------------------------- 1 | // Chapter 8 : Activity 2 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define DEBUG 0 12 | 13 | #if DEBUG 14 | #define PRINT(x) cerr << x 15 | #else 16 | #define PRINT(x) 17 | #endif 18 | 19 | using namespace std; 20 | 21 | vector>> found; 22 | 23 | int LCS_BruteForce(string A, string B, int i, int j, vector> subsequence) 24 | { 25 | if(i >= A.size() || j >= B.size()) 26 | { 27 | found.push_back(subsequence); 28 | 29 | //Terminate recursion and return length of subsequence 30 | return subsequence.size(); 31 | } 32 | 33 | // if A[i] = B[j]: 34 | if(A[i] == B[j]) 35 | { 36 | // Increase length of subsequence by 1 37 | subsequence.push_back({ i, j }); 38 | 39 | // Increment both i and j by 1 40 | return LCS_BruteForce(A, B, i + 1, j + 1, subsequence); 41 | } 42 | /* 43 | Option 1) Explore further possibilities with i + 1, and j 44 | Option 2) Explore further possibilities with i, and j + 1 45 | 46 | LCS from this state is equal to maximum value of Option 1 and Option 2 47 | */ 48 | 49 | return max(LCS_BruteForce(A, B, i + 1, j, subsequence), 50 | LCS_BruteForce(A, B, i, j + 1, subsequence)); 51 | } 52 | 53 | void PrintSubsequences(string A, string B) 54 | { 55 | // Lambda function for custom sorting logic 56 | sort(found.begin(), found.end(), [](auto a, auto b) 57 | { 58 | // Sort subsequences by length 59 | if(a.size() != b.size()) 60 | { 61 | return a.size() < b.size(); 62 | } 63 | 64 | // Sort subsequences of same size by lexicographical order of index 65 | return a < b; 66 | }); 67 | 68 | found.erase(unique(found.begin(), found.end()), found.end()); 69 | 70 | int previousSize = 0; 71 | 72 | for(auto subsequence : found) 73 | { 74 | if(subsequence.size() != previousSize) 75 | { 76 | previousSize = subsequence.size(); 77 | PRINT("SIZE = " << previousSize << endl); 78 | } 79 | // Fill with underscores as placeholder characters 80 | string a_seq(A.size(), '_'); 81 | string b_seq(B.size(), '_'); 82 | 83 | for(auto pair : subsequence) 84 | { 85 | // Fill in the blanks with the characters of each string that are part of the subsequence 86 | 87 | a_seq[pair.first] = A[pair.first]; 88 | b_seq[pair.second] = B[pair.second]; 89 | } 90 | PRINT("\t" << a_seq << " " << b_seq << endl); 91 | } 92 | } 93 | 94 | const int UNKNOWN = -1; 95 | 96 | int LCS_Memoization(string A, string B, int i, int j, vector> &memo) 97 | { 98 | if(i == 0 || j == 0) 99 | { 100 | return 0; 101 | } 102 | if(memo[i - 1][j - 1] != UNKNOWN) 103 | { 104 | return memo[i - 1][j - 1]; 105 | } 106 | 107 | if(A[i-1] == B[j-1]) 108 | { 109 | memo[i - 1][j - 1] = 1 + LCS_Memoization(A, B, i - 1, j - 1, memo); 110 | 111 | return memo[i - 1][j - 1]; 112 | } 113 | memo[i - 1][j - 1] = max(LCS_Memoization(A, B, i - 1, j, memo), 114 | LCS_Memoization(A, B, i, j - 1, memo)); 115 | 116 | return memo[i - 1][j - 1]; 117 | } 118 | 119 | vector types = 120 | { 121 | "BRUTE FORCE", 122 | "MEMOIZATION", 123 | "TABULATION" 124 | }; 125 | 126 | void GetTime(clock_t &timer, string type) 127 | { 128 | timer = clock() - timer; 129 | 130 | cout << "TIME TAKEN USING " << type << ": " << fixed << setprecision(5) << (float)timer / CLOCKS_PER_SEC << " SECONDS" << endl; 131 | 132 | timer = clock(); 133 | } 134 | 135 | int main() 136 | { 137 | string A, B; 138 | cin >> A >> B; 139 | 140 | int tests = 2; 141 | 142 | clock_t timer = clock(); 143 | 144 | for(int i = 0; i < tests; i++) 145 | { 146 | int LCS; 147 | 148 | switch(i) 149 | { 150 | case 0: 151 | { 152 | LCS = LCS_BruteForce(A, B, 0, 0, {}); 153 | 154 | #if DEBUG 155 | PrintSubsequences(A, B); 156 | #endif 157 | break; 158 | } 159 | case 1: 160 | { 161 | vector> memo(A.size(), vector(B.size(), UNKNOWN)); 162 | LCS = LCS_Memoization(A, B, A.size(), B.size(), memo); 163 | break; 164 | } 165 | } 166 | cout << "Length of the longest common subsequence of " << A << " and " << B << " is: " << LCS << endl; 167 | 168 | GetTime(timer, types[i]); 169 | cout << endl; 170 | } 171 | return 0; 172 | } 173 | /* 174 | 123456 QWERTY 175 | = 0 176 | 177 | ACBEBC ABCBC 178 | = 4 179 | 180 | AZYBYXCXW ZZAYYBXXXCWW 181 | = 6 182 | 183 | ABCABDBEFBA ABCBEFBEAB 184 | = 8 185 | 186 | ABZCYDABAZADAEA YABAZADBBEAAECYACAZ 187 | = 10 188 | */ 189 | 190 | -------------------------------------------------------------------------------- /Lesson8/Activity21/Activity 21.cp: -------------------------------------------------------------------------------- 1 | // Activity 21 2 | 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | int CountMelodicPermutations(vector melody, vector set) 9 | { 10 | unsigned int target = 0; 11 | 12 | for(auto note : set) 13 | { 14 | target |= note; 15 | } 16 | vector> DP(melody.size() + 1, vector(4096, 0)); 17 | 18 | // Base case -> empty set 19 | DP[0][0] = 1; 20 | 21 | for(int i = 1; i <= melody.size(); i++) 22 | { 23 | for(unsigned int subset = 0; subset < 4096; subset++) 24 | { 25 | // Keep results for previous values of i 26 | DP[i][subset] += DP[i - 1][subset]; 27 | 28 | // Add results for union of subset with melody[i-1] 29 | DP[i][subset | melody[i-1]] += DP[i - 1][subset]; 30 | } 31 | } 32 | 33 | // Solution 34 | return DP[melody.size()][target]; 35 | } 36 | 37 | vector ConvertNotes(vector notes) 38 | { 39 | map M = 40 | { 41 | {"A", 0}, 42 | {"A#", 1}, 43 | {"Bb", 1}, 44 | {"B", 2}, 45 | {"Cb", 2}, 46 | {"B#", 3}, 47 | {"C", 3}, 48 | {"C#", 4}, 49 | {"Db", 4}, 50 | {"D", 5}, 51 | {"D#", 6}, 52 | {"Eb", 6}, 53 | {"E", 7}, 54 | {"Fb", 7}, 55 | {"E#", 8}, 56 | {"F", 8}, 57 | {"F#", 9}, 58 | {"Gb", 9}, 59 | {"G", 10}, 60 | {"G#", 11}, 61 | {"Ab", 11} 62 | }; 63 | 64 | vector converted; 65 | 66 | for(auto note : notes) 67 | { 68 | converted.push_back(1 << M[note]); // Map to powers of 2 69 | } 70 | return converted; 71 | } 72 | 73 | int main() 74 | { 75 | int melodyLength; 76 | int setLength; 77 | 78 | cin >> melodyLength; 79 | 80 | vector melody(melodyLength); 81 | 82 | for(int i = 0; i < melodyLength; i++) 83 | { 84 | cin >> melody[i]; 85 | } 86 | 87 | cin >> setLength; 88 | 89 | vector set(setLength); 90 | 91 | for(int i = 0; i < setLength; i++) 92 | { 93 | cin >> set[i]; 94 | } 95 | int count = CountMelodicPermutations(ConvertNotes(melody), ConvertNotes(set)); 96 | 97 | cout << count << endl; 98 | 99 | return 0; 100 | } 101 | -------------------------------------------------------------------------------- /Lesson8/Exercise36/Exercise36.cpp: -------------------------------------------------------------------------------- 1 | // Exercise 36 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define DEBUG 1 8 | 9 | #if DEBUG 10 | #define PRINT(x) cerr << x 11 | #else 12 | #define PRINT(x) 13 | #endif 14 | 15 | using namespace std; 16 | 17 | void GetAllSubsets(vector set, vector subset, int index, vector>> &allSubsets) 18 | { 19 | if(index == set.size()) 20 | { 21 | allSubsets[subset.size()].push_back(subset); 22 | return; 23 | } 24 | GetAllSubsets(set, subset, index + 1, allSubsets); 25 | 26 | subset.push_back(set[index]); 27 | 28 | GetAllSubsets(set, subset, index + 1, allSubsets); 29 | } 30 | 31 | bool SubsetSum_BruteForce(vector set, int target) 32 | { 33 | vector>> allSubsets(set.size() + 1); 34 | 35 | GetAllSubsets(set, {}, 0, allSubsets); 36 | 37 | for(int size = 0; size <= set.size(); size++) 38 | { 39 | PRINT("SIZE = " << size << endl); 40 | 41 | for(auto subset : allSubsets[size]) 42 | { 43 | PRINT("\t{ "); 44 | 45 | int sum = 0; 46 | 47 | for(auto number : subset) 48 | { 49 | sum += number; 50 | 51 | PRINT(number << " "); 52 | } 53 | PRINT("} = " << sum << endl); 54 | 55 | if(sum == target) return true; 56 | } 57 | } 58 | return false; 59 | } 60 | 61 | int main() 62 | { 63 | vector set = { 13, 79, 45, 29 }; 64 | 65 | int target = 1000000; 66 | 67 | bool found = SubsetSum_BruteForce(set, target); 68 | 69 | if(found) 70 | { 71 | cout << "Subset with sum " << target << " was found in the set." << endl; 72 | } 73 | else 74 | { 75 | cout << "Subset with sum " << target << " was not found in the set." << endl; 76 | } 77 | 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /Lesson8/Exercise37/Exercise37.cpp: -------------------------------------------------------------------------------- 1 | // Chapter 8 : Exercise 2 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define DEBUG 0 10 | 11 | #if DEBUG 12 | #define PRINT(x) cerr << x 13 | #else 14 | #define PRINT(x) 15 | #endif 16 | 17 | using namespace std; 18 | 19 | vector> memo; 20 | 21 | const int UNKNOWN = -1; 22 | 23 | void GetAllSubsets(vector set, vector subset, int index, vector>> &allSubsets) 24 | { 25 | if(index == set.size()) 26 | { 27 | allSubsets[subset.size()].push_back(subset); 28 | return; 29 | } 30 | GetAllSubsets(set, subset, index + 1, allSubsets); 31 | 32 | subset.push_back(set[index]); 33 | 34 | GetAllSubsets(set, subset, index + 1, allSubsets); 35 | } 36 | 37 | bool SubsetSum_BruteForce(vector set, int target) 38 | { 39 | vector>> allSubsets(set.size() + 1); 40 | 41 | GetAllSubsets(set, {}, 0, allSubsets); 42 | 43 | for(int size = 0; size <= set.size(); size++) 44 | { 45 | PRINT("SIZE = " << size << endl); 46 | 47 | for(auto subset : allSubsets[size]) 48 | { 49 | PRINT("\t{ "); 50 | 51 | int sum = 0; 52 | 53 | for(auto number : subset) 54 | { 55 | sum += number; 56 | 57 | PRINT(number << " "); 58 | } 59 | PRINT("} = " << sum << endl); 60 | 61 | if(sum == target) return true; 62 | } 63 | } 64 | return false; 65 | } 66 | 67 | bool SubsetSum_Backtracking(vector set, int sum, int i) 68 | { 69 | // The sum has been found 70 | 71 | if(sum == 0) 72 | { 73 | return true; 74 | } 75 | 76 | // End of set is reached, or sum would be exceeded beyond this point 77 | 78 | if(i == set.size() || set[i] > sum) 79 | { 80 | return false; 81 | } 82 | 83 | // Case 1: Add to sum 84 | // Case 2: Leave as-is 85 | 86 | return SubsetSum_Backtracking(set, sum - set[i], i + 1) 87 | || SubsetSum_Backtracking(set, sum, i + 1); 88 | } 89 | 90 | vector types = 91 | { 92 | "BRUTE FORCE", 93 | "BACKTRACKING", 94 | "MEMOIZATION", 95 | "TABULATION" 96 | }; 97 | 98 | const int UNKNOWN = INT_MAX; 99 | 100 | void GetTime(clock_t &timer, string type) 101 | { 102 | // Subtract timer from current time to get time elapsed 103 | timer = clock() - timer; 104 | 105 | // Display seconds elapsed 106 | cout << "TIME TAKEN USING " << type << ": " << fixed << setprecision(5) << (float)timer / CLOCKS_PER_SEC << endl; 107 | 108 | timer = clock(); // Reset timer 109 | } 110 | 111 | int main() 112 | { 113 | vector set = { 16, 1058, 22, 13, 46, 55, 3, 92, 47, 7, 98, 367, 807, 106, 333, 85, 577, 9, 3059 }; 114 | 115 | int target = 6076; 116 | int tests = 2; 117 | 118 | clock_t timer = clock(); 119 | 120 | sort(set.begin(), set.end()); 121 | 122 | for(int i = 0; i < tests; i++) 123 | { 124 | bool found; 125 | 126 | switch(i) 127 | { 128 | case 0: found = SubsetSum_BruteForce(set, target); break; 129 | case 1: found = SubsetSum_Backtracking(set, target, 0); break; 130 | } 131 | 132 | if(found) 133 | { 134 | cout << "Subset with sum " << target << " was found in the set." << endl; 135 | } 136 | else 137 | { 138 | cout << "Subset with sum " << target << " was not found in the set." << endl; 139 | } 140 | GetTime(timer, types[i]); 141 | cout << endl; 142 | } 143 | 144 | return 0; 145 | } 146 | 147 | -------------------------------------------------------------------------------- /Lesson8/Exercise38/Exercise38.cp: -------------------------------------------------------------------------------- 1 | // Chapter 38 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define DEBUG 0 10 | 11 | #if DEBUG 12 | #define PRINT(x) cerr << x 13 | #else 14 | #define PRINT(x) 15 | #endif 16 | 17 | using namespace std; 18 | 19 | const int UNKNOWN = -1; 20 | 21 | void GetAllSubsets(vector set, vector subset, int index, vector>> &allSubsets) 22 | { 23 | if(index == set.size()) 24 | { 25 | allSubsets[subset.size()].push_back(subset); 26 | return; 27 | } 28 | GetAllSubsets(set, subset, index + 1, allSubsets); 29 | 30 | subset.push_back(set[index]); 31 | 32 | GetAllSubsets(set, subset, index + 1, allSubsets); 33 | } 34 | 35 | bool SubsetSum_BruteForce(vector set, int target) 36 | { 37 | vector>> allSubsets(set.size() + 1); 38 | 39 | GetAllSubsets(set, {}, 0, allSubsets); 40 | 41 | for(int size = 0; size <= set.size(); size++) 42 | { 43 | PRINT("SIZE = " << size << endl); 44 | 45 | for(auto subset : allSubsets[size]) 46 | { 47 | PRINT("\t{ "); 48 | 49 | int sum = 0; 50 | 51 | for(auto number : subset) 52 | { 53 | sum += number; 54 | 55 | PRINT(number << " "); 56 | } 57 | PRINT("} = " << sum << endl); 58 | 59 | if(sum == target) return true; 60 | } 61 | } 62 | return false; 63 | } 64 | 65 | bool SubsetSum_Backtracking(vector set, int sum, int i) 66 | { 67 | // The sum has been found 68 | 69 | if(sum == 0) 70 | { 71 | return true; 72 | } 73 | 74 | // End of set is reached, or sum would be exceeded beyond this point 75 | 76 | if(i == set.size() || set[i] > sum) 77 | { 78 | return false; 79 | } 80 | 81 | // Case 1: Add to sum 82 | // Case 2: Leave as-is 83 | 84 | return SubsetSum_Backtracking(set, sum - set[i], i + 1) 85 | || SubsetSum_Backtracking(set, sum, i + 1); 86 | } 87 | 88 | bool SubsetSum_Memoization(vector &set, int sum, int i, vector> &memo) 89 | { 90 | // The sum has been found 91 | if(sum == 0) 92 | { 93 | return true; 94 | } 95 | 96 | // End of set is reached, or sum would be exceeded beyond this point 97 | if(i == set.size() || set[i] > sum) 98 | { 99 | return false; 100 | } 101 | 102 | // Is this state cached? 103 | if(memo[i][sum] == UNKNOWN) 104 | { 105 | // Get solution for this state and cache it 106 | 107 | bool append = SubsetSum_Memoization(set, sum - set[i], i + 1, memo); 108 | bool ignore = SubsetSum_Memoization(set, sum, i + 1, memo); 109 | 110 | memo[i][sum] = append || ignore; 111 | } 112 | // Return cached value 113 | return memo[i][sum]; 114 | } 115 | 116 | vector types = 117 | { 118 | "BRUTE FORCE", 119 | "BACKTRACKING", 120 | "MEMOIZATION", 121 | "TABULATION" 122 | }; 123 | 124 | void GetTime(clock_t &timer, string type) 125 | { 126 | // Subtract timer from current time to get time elapsed 127 | timer = clock() - timer; 128 | 129 | // Display seconds elapsed 130 | cout << "TIME TAKEN USING " << type << ": " << fixed << setprecision(5) << (float)timer / CLOCKS_PER_SEC << endl; 131 | 132 | timer = clock(); // Reset timer 133 | } 134 | 135 | int main() 136 | { 137 | vector set = { 16, 1058, 22, 13, 46, 55, 3, 92, 47, 7, 98, 367, 807, 106, 333, 85, 577, 9, 3059 }; 138 | 139 | int target = 6799; 140 | int tests = 3; 141 | 142 | clock_t timer = clock(); 143 | 144 | sort(set.begin(), set.end()); 145 | 146 | for(int i = 0; i < tests; i++) 147 | { 148 | bool found; 149 | 150 | switch(i) 151 | { 152 | case 0: found = SubsetSum_BruteForce(set, target); break; 153 | case 1: found = SubsetSum_Backtracking(set, target, 0); break; 154 | case 2: 155 | { 156 | // Initialize memoization table 157 | vector> memo(set.size(), vector(7000, UNKNOWN)); 158 | 159 | found = SubsetSum_Memoization(set, target, 0, memo); 160 | break; 161 | } 162 | } 163 | 164 | if(found) 165 | { 166 | cout << "Subset with sum " << target << " was found in the set." << endl; 167 | } 168 | else 169 | { 170 | cout << "Subset with sum " << target << " was not found in the set." << endl; 171 | } 172 | GetTime(timer, types[i]); 173 | cout << endl; 174 | } 175 | return 0; 176 | } 177 | 178 | -------------------------------------------------------------------------------- /Lesson8/Exercise40/Exercise40.cpp: -------------------------------------------------------------------------------- 1 | // Exercise 40 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define DEBUG 1 12 | 13 | #if DEBUG 14 | #define PRINT(x) cerr << x 15 | #else 16 | #define PRINT(x) 17 | #endif 18 | 19 | using namespace std; 20 | 21 | vector>> found; 22 | 23 | int LCS_BruteForce(string A, string B, int i, int j, vector> subsequence) 24 | { 25 | if(i >= A.size() || j >= B.size()) 26 | { 27 | found.push_back(subsequence); 28 | 29 | //Terminate recursion and return length of subsequence 30 | return subsequence.size(); 31 | } 32 | 33 | // if A[i] = B[j]: 34 | if(A[i] == B[j]) 35 | { 36 | // Increase length of subsequence by 1 37 | subsequence.push_back({ i, j }); 38 | 39 | // Increment both i and j by 1 40 | return LCS_BruteForce(A, B, i + 1, j + 1, subsequence); 41 | } 42 | /* 43 | Option 1) Explore further possibilities with i + 1, and j 44 | Option 2) Explore further possibilities with i, and j + 1 45 | 46 | LCS from this state is equal to maximum value of Option 1 and Option 2 47 | */ 48 | 49 | return max(LCS_BruteForce(A, B, i + 1, j, subsequence), 50 | LCS_BruteForce(A, B, i, j + 1, subsequence)); 51 | } 52 | 53 | void PrintSubsequences(string A, string B) 54 | { 55 | // Lambda function for custom sorting logic 56 | sort(found.begin(), found.end(), [](auto a, auto b) 57 | { 58 | // Sort subsequences by length 59 | if(a.size() != b.size()) 60 | { 61 | return a.size() < b.size(); 62 | } 63 | 64 | // Sort subsequences of same size by lexicographical order of index 65 | return a < b; 66 | }); 67 | 68 | found.erase(unique(found.begin(), found.end()), found.end()); 69 | 70 | int previousSize = 0; 71 | 72 | for(auto subsequence : found) 73 | { 74 | if(subsequence.size() != previousSize) 75 | { 76 | previousSize = subsequence.size(); 77 | PRINT("SIZE = " << previousSize << endl); 78 | } 79 | // Fill with underscores as placeholder characters 80 | string a_seq(A.size(), '_'); 81 | string b_seq(B.size(), '_'); 82 | 83 | for(auto pair : subsequence) 84 | { 85 | // Fill in the blanks with the characters of each string that are part of the subsequence 86 | 87 | a_seq[pair.first] = A[pair.first]; 88 | b_seq[pair.second] = B[pair.second]; 89 | } 90 | PRINT("\t" << a_seq << " " << b_seq << endl); 91 | } 92 | } 93 | 94 | int main() 95 | { 96 | string A, B; 97 | cin >> A >> B; 98 | 99 | int LCS = LCS_BruteForce(A, B, 0, 0, {}); 100 | 101 | cout << "Length of the longest common subsequence of " << A << " and " << B << " is: " << LCS << endl; 102 | 103 | PrintSubsequences(A, B); 104 | } 105 | 106 | 107 | -------------------------------------------------------------------------------- /Lesson9/Activity22/Activity22.cpp: -------------------------------------------------------------------------------- 1 | // Chapter 9 : Activity 1 2 | 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | struct Product 9 | { 10 | int quantity; 11 | int price; 12 | int value; 13 | 14 | Product(int q, int c, int v) 15 | : quantity(q), price(c), value(v) {} 16 | }; 17 | 18 | int main() 19 | { 20 | int N, budget, capacity; 21 | cin >> N >> budget >> capacity; 22 | 23 | vector products; 24 | 25 | for(int i = 0; i < N; i++) 26 | { 27 | int quantity, cost, value; 28 | cin >> quantity >> cost >> value; 29 | 30 | products.push_back(Product(quantity, cost, value)); 31 | } 32 | vector>> DP(N + 1, vector>(budget + 1, vector(capacity + 1, 0))); 33 | 34 | for(int i = 1; i <= N; i++) 35 | { 36 | Product product = products[i-1]; 37 | 38 | for(int cost = 0; cost <= budget; cost++) 39 | { 40 | for(int count = 0; count <= capacity; count++) 41 | { 42 | if(cost < product.price || count < product.quantity) 43 | { 44 | DP[i][cost][count] = DP[i-1][cost][count]; 45 | } 46 | else 47 | { 48 | DP[i][cost][count] = max 49 | ( 50 | DP[i-1][cost][count], 51 | DP[i-1][cost - product.price][count - product.quantity] + product.value 52 | ); 53 | } 54 | } 55 | } 56 | } 57 | cout << DP[N][budget][capacity] << endl; 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /Lesson9/Exercise41/Exercise41.cpp: -------------------------------------------------------------------------------- 1 | // Exercise 41 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | int Knapsack_01(int items, int capacity, vector values, vector weight) 10 | { 11 | vector> DP(items + 1, vector(capacity + 1, 0)); 12 | 13 | for(int i = 1; i <= items; i++) 14 | { 15 | int currentWeight = weight[i-1]; 16 | int currentValue = values[i-1]; 17 | 18 | for(int totalWeight = 1; totalWeight <= capacity; totalWeight++) 19 | { 20 | if(totalWeight < currentWeight) 21 | { 22 | DP[i][totalWeight] = DP[i-1][totalWeight]; 23 | } 24 | else 25 | { 26 | DP[i][totalWeight] = max(DP[i-1][totalWeight], 27 | DP[i-1][totalWeight - currentWeight] + currentValue); 28 | } 29 | } 30 | } 31 | return DP[items][capacity]; 32 | } 33 | 34 | int main() 35 | { 36 | int items, capacity; 37 | 38 | cin >> items >> capacity; 39 | 40 | vector values(items), weight(items); 41 | 42 | for(auto &v : values) cin >> v; 43 | for(auto &w : weight) cin >> w; 44 | 45 | int result = Knapsack_01(items, capacity, values, weight); 46 | 47 | cout << "The highest-valued subset of items that can fit in the knapsack is: " << result << endl; 48 | 49 | return 0; 50 | } 51 | 52 | /* 53 | 8 66 54 | 20 4 89 12 5 50 8 13 55 | 5 23 9 72 16 14 32 4 56 | */ 57 | -------------------------------------------------------------------------------- /Lesson9/Exercise42/Exercise42.cpp: -------------------------------------------------------------------------------- 1 | // Exercise 42 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | int UnboundedKnapsack(int items, int capacity, vector values, vector weight) 8 | { 9 | vector DP(capacity + 1, 0); 10 | 11 | for(int w = 0; w <= capacity; w++) 12 | { 13 | for(int i = 0; i < items; i++) 14 | { 15 | if(weight[i] <= w) 16 | { 17 | DP[w] = max(DP[w], DP[w - weight[i]] + values[i]); 18 | } 19 | } 20 | } 21 | return DP[capacity]; 22 | } 23 | 24 | int main() 25 | { 26 | int items, capacity; 27 | cin >> items >> capacity; 28 | 29 | vector weight(items), values(items); 30 | 31 | for(auto &v : values) cin >> v; 32 | for(auto &w : weight) cin >> w; 33 | 34 | int result = UnboundedKnapsack(items, capacity, values, weight); 35 | 36 | cout << "Maximum value of items that can be contained in the knapsack: " << result << endl; 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /Lesson9/Exercise43/Exercise43.cpp: -------------------------------------------------------------------------------- 1 | // Exercise 43 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | const int UNKNOWN = 1e9; 10 | 11 | int V, E; 12 | vector> weight; 13 | vector> adj; 14 | 15 | map, int> memo; 16 | 17 | int ShortestPath_Memoization(int depth, int node, vector> &adj, vector> &weight) 18 | { 19 | // Check if key exists in map 20 | if(memo.find({node, depth}) != memo.end()) 21 | { 22 | return memo[{node, depth}]; 23 | } 24 | memo[{node, depth}] = UNKNOWN; 25 | 26 | // Iterate through adjacent edges 27 | for(auto next : adj[node]) 28 | { 29 | int w = weight[node][next]; 30 | int dist = ShortestPath_Memoization(depth - 1, next, adj, weight) + w; 31 | 32 | memo[{node, depth}] = min(memo[{node, depth}], dist); 33 | } 34 | return memo[{node, depth}]; 35 | } 36 | 37 | vector GetShortestPaths(int source) 38 | { 39 | vector> adj_t(V); 40 | vector> weight_t(V, vector(V, UNKNOWN)); 41 | 42 | memo.clear(); 43 | 44 | for(int i = 0; i < V; i++) 45 | { 46 | // Create transpose of graph 47 | for(auto j : adj[i]) 48 | { 49 | adj_t[j].push_back(i); 50 | weight_t[j][i] = weight[i][j]; 51 | } 52 | // Base case -- shortest distance from source to itself is zero at any depth 53 | 54 | memo[{source, i}] = 0; 55 | 56 | if(i != source) 57 | { 58 | // If any node other than the source has been reached after V - 1 59 | // iterations, no path exists 60 | 61 | memo[{i, 0}] = UNKNOWN; 62 | } 63 | } 64 | 65 | vector distance(V); 66 | 67 | for(int i = 0; i < V; i++) 68 | { 69 | distance[i] = ShortestPath_Memoization(V - 1, i, adj_t, weight_t); 70 | } 71 | return distance; 72 | } 73 | 74 | int main() 75 | { 76 | cin >> V >> E; 77 | 78 | weight.resize(V, vector(V, UNKNOWN)); 79 | adj.resize(V); 80 | 81 | while(E--) 82 | { 83 | int u, v, w; 84 | cin >> u >> v >> w; 85 | 86 | adj[u].push_back(v); 87 | weight[u][v] = w; 88 | } 89 | 90 | vector> paths(V); 91 | 92 | for(int i = 0; i < V; i++) 93 | { 94 | paths[i] = GetShortestPaths(i); 95 | } 96 | 97 | cout << "The shortest distances between each pair of vertices are:" << endl; 98 | 99 | for(int i = 0; i < V; i++) 100 | { 101 | cout << i << ": "; 102 | 103 | for(int j = 0; j < V; j++) 104 | { 105 | (paths[i][j] == UNKNOWN) ? cout << "- " 106 | : cout << paths[i][j] << " "; 107 | } 108 | cout << endl; 109 | } 110 | return 0; 111 | } 112 | /* 113 | 8 20 114 | 0 1 387 115 | 0 3 38 116 | 0 5 471 117 | 1 0 183 118 | 1 4 796 119 | 2 5 715 120 | 3 0 902 121 | 3 1 712 122 | 3 2 154 123 | 3 6 425 124 | 4 3 834 125 | 4 6 214 126 | 5 0 537 127 | 5 3 926 128 | 5 4 125 129 | 5 6 297 130 | 6 1 863 131 | 6 7 248 132 | 7 0 73 133 | 7 3 874 134 | 135 | */ 136 | -------------------------------------------------------------------------------- /Lesson9/Exercise44/Exercise44.cpp: -------------------------------------------------------------------------------- 1 | // Exercise 44 2 | 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | const int UNKNOWN = 1e9; 8 | 9 | vector> FloydWarshall(int V, vector> weight) 10 | { 11 | vector> distance(V, vector(V, UNKNOWN)); 12 | 13 | for(int i = 0; i < V; i++) 14 | { 15 | for(int j = 0; j < V; j++) 16 | { 17 | distance[i][j] = weight[i][j]; 18 | } 19 | distance[i][i] = 0; 20 | } 21 | 22 | for(int mid = 0; mid < V; mid++) 23 | { 24 | for(int start = 0; start < V; start++) 25 | { 26 | for(int end = 0; end < V; end++) 27 | { 28 | if(distance[start][mid] + distance[mid][end] < distance[start][end]) 29 | { 30 | distance[start][end] = distance[start][mid] + distance[mid][end]; 31 | } 32 | } 33 | } 34 | } 35 | 36 | for(int i = 0; i < V; i++) 37 | { 38 | if(distance[i][i] < 0) 39 | { 40 | return {}; 41 | } 42 | } 43 | return distance; 44 | } 45 | 46 | int main() 47 | { 48 | int V, E; 49 | cin >> V >> E; 50 | 51 | vector> weight(V, vector(V, UNKNOWN)); 52 | 53 | for(int i = 0; i < E; i++) 54 | { 55 | int u, v, w; 56 | cin >> u >> v >> w; 57 | 58 | weight[u][v] = w; 59 | } 60 | 61 | vector> distance = FloydWarshall(V, weight); 62 | 63 | if(distance.empty()) 64 | { 65 | cout << "NEGATIVE CYCLE FOUND" << endl; 66 | return 0; 67 | } 68 | 69 | for(int i = 0; i < V; i++) 70 | { 71 | cout << i << endl; 72 | 73 | for(int j = 0; j < V; j++) 74 | { 75 | cout << "\t" << j << ": "; 76 | 77 | (distance[i][j] == UNKNOWN) ? cout << "_" << endl 78 | : cout << distance[i][j] << endl; 79 | } 80 | } 81 | return 0; 82 | } 83 | /* 84 | 7 9 85 | 0 1 3 86 | 1 2 5 87 | 1 3 10 88 | 1 5 -4 89 | 2 4 2 90 | 3 2 -7 91 | 4 1 -3 92 | 5 6 -8 93 | 6 0 12 94 | */ 95 | /* 96 | 6 8 97 | 0 1 3 98 | 1 3 -8 99 | 2 1 3 100 | 2 4 2 101 | 2 5 5 102 | 3 2 3 103 | 4 5 -1 104 | 5 1 8 105 | */ 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![GitHub issues](https://img.shields.io/github/issues/TrainingByPackt/CPP-Data-Structures-and-Algorithms.svg)](https://github.com/TrainingByPackt/CPP-Data-Structures-and-Algorithm-Design-Principles/issues) 2 | [![GitHub forks](https://img.shields.io/github/forks/TrainingByPackt/CPP-Data-Structures-and-Algorithms.svg)](https://github.com/TrainingByPackt/CPP-Data-Structures-and-Algorithm-Design-Principles/network) 3 | [![GitHub stars](https://img.shields.io/github/stars/TrainingByPackt/CPP-Data-Structures-and-Algorithms.svg)](https://github.com/TrainingByPackt/CPP-Data-Structures-and-Algorithm-Design-Principles/stargazers) 4 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/TrainingByPackt/CPP-Data-Structures-and-Algorithm-Design-Principles/pulls) 5 | 6 | # C++ Data Structures and Algorithm Design Principles 7 | C++ is a mature multi-paradigm programming language that enables you to write high-level code with a high degree of control over the hardware. Today, significant parts of software infrastructure, including databases, browsers, multimedia frameworks, and GUI toolkits, are written in C++. 8 | 9 | This course starts by introducing C++ data structures and how to store data using linked lists, arrays, stacks, and queues. In later chapters, the course explains the basic algorithm design paradigms, such as the greedy approach and the divide-and-conquer approach, which are used to solve a large variety of computational problems. Finally, you will learn the advanced technique of dynamic programming to develop optimized implementations of several algorithms discussed in the course. 10 | 11 | By the end of this course, you will have learned how to implement standard data structures and algorithms in efficient and scalable C++ 14 code. 12 | 13 | ### What you will learn 14 | * Build applications using hash tables, dictionaries, and sets. 15 | * Implement a URL shortening service using a bloom filter. 16 | * Implement common algorithms, such as heap sort and merge sort in string data types. 17 | * Use C++ template metaprogramming to write code libraries. 18 | * Explore how modern hardware affects the actual run-time performance of programs. 19 | * Use appropriate modern C++ idioms like std:: array instead of C-style arrays. 20 | 21 | ### The examples of this title have been tested on the Windows, Linux and MacOS operating systems. 22 | 23 | ### Software Requirements 24 | You'll also need the following software installed in advance: 25 | * Operating system: Windows 7 SP1 32/64-bit, Windows 8.1 32/64-bit, or Windows 10 32/64-bit, Ubuntu 14.04 or later, or macOS Sierra or later 26 | * Browser: Google Chrome or Mozilla Firefox 27 | * Any modern compiler and IDE (optional) that supports the C++ 14 standard. 28 | * Boost C++ Libraries 29 | * CMake 30 | --------------------------------------------------------------------------------