├── .gitignore
├── 00-TableOfContents.ipynb
├── AlgorithmAnalysis.ipynb
├── AllPairsSP-Floyd.ipynb
├── BinaryTrees.ipynb
├── DAG-TopologicalSort.ipynb
├── GeneralTreesUnionFind.ipynb
├── GraphsImplementations.ipynb
├── GraphsIntro.ipynb
├── GraphsShortestPaths.ipynb
├── Hashing.ipynb
├── Heaps-PriorityQueues.ipynb
├── Introduction.ipynb
├── LICENSE
├── MSTKruskals.ipynb
├── MathematicalBackground.ipynb
├── README.md
├── SearchAlgorithms.ipynb
├── Sorting.ipynb
├── SpanningTreesPrims.ipynb
├── demo-programs
├── binaryTree
│ └── BST.cpp
└── cbt
│ ├── CBT.cpp
│ └── CBT.h
├── pdfs
├── 00-Introduction.pdf
├── AllPairsSP-Floyd.pdf
├── BinaryTrees.pdf
├── DAG-TopologicalSort.pdf
├── GeneralTreesUnionFind.pdf
├── GraphsImplementations.pdf
├── GraphsIntro.pdf
├── GraphsShortestPaths.pdf
├── Hashing.pdf
├── Heaps-PriorityQueues.pdf
├── MSTKruskals.pdf
├── Sorting.pdf
└── SpanningTreesPrims.pdf
└── resources
├── BST-delete-Case1.png
├── BST-delete-Case3.png
├── BST-delete-case2.png
├── BSTShape2.png
├── BinarySearchTreeFiga.png
├── Bubble-sort-example.gif
├── DAG.png
├── Dijkstra_Animation.gif
├── Dijkstras_progress_animation.gif
├── DirectedGraphImp.png
├── GeneralTrees.png
├── Insertion-sort-example.gif
├── Kruskals.png
├── MCST.png
├── Merge-sort-example.gif
├── Merge_sort_algorithm_diagram.png
├── OOPCM.png
├── OpenHashing.png
├── ParentPtrTree.png
├── UndirectedGraphImp.png
├── binary-tree-cartoon.png
├── binaryTree1.png
├── binarytree.gif
├── clique.png
├── completeOrFull.png
├── connectedGraphs.png
├── denseGraph.png
├── directedGraphRepresentation.png
├── full-binary-tree.png
├── fullAndCompleteBT.png
├── graph.png
├── graphEx1.png
├── graphPathCycles.png
├── graphTypes.png
├── growthRates.png
├── growthRatesZoom.png
├── growthrates.gif
├── k-path.png
├── makeHeapAfter.png
├── makeHeapAlgorithm.png
├── makeHeapBefore.png
├── pushHeap.png
├── pushvsbuildheap.png
├── seqSearchBestWorstAvg.png
├── shellsortA.png
├── shellsortB.png
├── shellsortC.png
├── sparseGraph.png
├── sssp.png
├── topoSort.png
├── undirectedGraphRep.png
└── weightedGraphRep.png
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.so
16 | *.dylib
17 | *.dll
18 |
19 | # Fortran module files
20 | *.mod
21 | *.smod
22 |
23 | # Compiled Static libraries
24 | *.lai
25 | *.la
26 | *.a
27 | *.lib
28 |
29 | # Executables
30 | *.exe
31 | *.out
32 | *.app
33 |
34 | # Byte-compiled / optimized / DLL files
35 | __pycache__/
36 | *.py[cod]
37 | *$py.class
38 |
39 | # C extensions
40 | *.so
41 |
42 | # Distribution / packaging
43 | .Python
44 | build/
45 | develop-eggs/
46 | dist/
47 | downloads/
48 | eggs/
49 | .eggs/
50 | lib/
51 | lib64/
52 | parts/
53 | sdist/
54 | var/
55 | wheels/
56 | *.egg-info/
57 | .installed.cfg
58 | *.egg
59 | MANIFEST
60 |
61 | # PyInstaller
62 | # Usually these files are written by a python script from a template
63 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
64 | *.manifest
65 | *.spec
66 |
67 | # Installer logs
68 | pip-log.txt
69 | pip-delete-this-directory.txt
70 |
71 | # Unit test / coverage reports
72 | htmlcov/
73 | .tox/
74 | .coverage
75 | .coverage.*
76 | .cache
77 | nosetests.xml
78 | coverage.xml
79 | *.cover
80 | .hypothesis/
81 | .pytest_cache/
82 |
83 | # Translations
84 | *.mo
85 | *.pot
86 |
87 | # Django stuff:
88 | *.log
89 | local_settings.py
90 | db.sqlite3
91 |
92 | # Flask stuff:
93 | instance/
94 | .webassets-cache
95 |
96 | # Scrapy stuff:
97 | .scrapy
98 |
99 | # Sphinx documentation
100 | docs/_build/
101 |
102 | # PyBuilder
103 | target/
104 |
105 | # Jupyter Notebook
106 | .ipynb_checkpoints
107 |
108 | # pyenv
109 | .python-version
110 |
111 | # celery beat schedule file
112 | celerybeat-schedule
113 |
114 | # SageMath parsed files
115 | *.sage.py
116 |
117 | # Environments
118 | .env
119 | .venv
120 | env/
121 | venv/
122 | ENV/
123 | env.bak/
124 | venv.bak/
125 |
126 | # Spyder project settings
127 | .spyderproject
128 | .spyproject
129 |
130 | # Rope project settings
131 | .ropeproject
132 |
133 | # mkdocs documentation
134 | /site
135 |
136 | # mypy
137 | .mypy_cache/
138 |
139 | # others
140 | *.DS_Store
141 | *.pickle
142 | *.db
143 | .vscode/
144 | .ipynb_checkpoints/
145 | *.pickle
146 | __pycache__/
147 |
148 |
--------------------------------------------------------------------------------
/00-TableOfContents.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# CS3: Intro to Algorithms & Applications using C++\n",
8 | "\n",
9 | "## Table of Contents\n",
10 | "\n",
11 | "1. **[CS2 Review](https://github.com/rambasnet/cs2notebooks)**
\n",
12 | "2. **[Kattis Demos & Automated Testing](https://github.com/rambasnet/kattisdemos)**
\n",
13 | "3. **[STL Containers & Algorithms Libraries](https://github.com/rambasnet/stl-notebooks)**
\n",
14 | "4. **[CS3 Introduction](#intro)**
\n",
15 | "5. **[Mathematical Background](./MathematicalBackground.ipynb)**
\n",
16 | "6. **[Algorithm Analysis](./AlgorithmAnalysis.ipynb)**
\n",
17 | "7. **[Search Algorithms](./SearchAlgorithms.ipynb)**
\n",
18 | "8. **[Sorting Algorithms](./Sorting.ipynb)**
\n",
19 | "9. **[Binary Trees](./BinaryTrees.ipynb)**
\n",
20 | "10. **[Heaps and Priority Queues](./Heaps-PriorityQueues.ipynb)**
\n",
21 | "11. **[Graphs Introduction](./GraphsIntro.ipynb)**
\n",
22 | "12. **[Graphs Implementations & Traversals](./GraphsImplementations.ipynb)**
\n",
23 | "13. **[DAG Topological Sort](./DAG-TopologicalSort.ipynb)**
\n",
24 | "14. **[Graphs Shortest-Paths Problems](./GraphsShortestPaths.ipynb)**
\n",
25 | "15. **[Minimum Spanning Trees & Prim's Algorithm](./SpanningTreesPrims.ipynb)**
\n",
26 | "16. **[General Trees & Union/Find Parent Pointer Trees](./GeneralTreesUnionFind.ipynb)**
\n",
27 | "17. **[MST Kruskal's Algorithm](./MSTKruskals.ipynb)**
\n",
28 | "18. **[All-Pairs Shortest Paths](./AllPairsSP-Floyd.ipynb)**
\n",
29 | "19. **[Hashing](./Hashing.ipynb)**
"
30 | ]
31 | },
32 | {
33 | "cell_type": "code",
34 | "execution_count": null,
35 | "metadata": {},
36 | "outputs": [],
37 | "source": []
38 | }
39 | ],
40 | "metadata": {
41 | "kernelspec": {
42 | "display_name": "C++14",
43 | "language": "C++14",
44 | "name": "xcpp14"
45 | },
46 | "language_info": {
47 | "codemirror_mode": "text/x-c++src",
48 | "file_extension": ".cpp",
49 | "mimetype": "text/x-c++src",
50 | "name": "c++",
51 | "version": "14"
52 | }
53 | },
54 | "nbformat": 4,
55 | "nbformat_minor": 4
56 | }
57 |
--------------------------------------------------------------------------------
/AllPairsSP-Floyd.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# All-Pairs Shortest Paths\n",
8 | "https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/Floyd.html\n",
9 | "\n",
10 | "## Table of Contents\n",
11 | "- **[Problem Statement](#intro)**
\n",
12 | "- **[Floyd's Algorithm](#floyd)**
"
13 | ]
14 | },
15 | {
16 | "cell_type": "markdown",
17 | "metadata": {},
18 | "source": [
19 | "## All-pairs shortest path problem\n",
20 | "- find the shortest distance between all pairs of vertices in the graph\n",
21 | "- for every $u, v \\in V$, calculate $d(u, v)$\n",
22 | "- one solution:\n",
23 | " - from each $v \\in V$, run Dijkstra's algorithm starting from $v$\n",
24 | " - if $G$ is sparse, (i.e. $|E| = \\Theta(|V|)$), Dijkstra's algorithm has the cost of $\\Theta(|V|^2+|V||E|log|V|)= \\Theta(|V|^2log|V|)$ using priority queue; so all-pairs will cost $\\Theta|V|^3log|V|$\n",
25 | " - if $G$ is dense, Dijkstra's algorithm (MinVertex version), yields cost of $\\Theta(|V|^3)$"
26 | ]
27 | },
28 | {
29 | "cell_type": "markdown",
30 | "metadata": {},
31 | "source": [
32 | "## Floyd's Algorithm\n",
33 | "- regardless the number of edges, Floyd's algorithm yields cost of $\\Theta|V|^3$\n",
34 | "- applies dynamic programming technique (avoids repeatedly solving the same subproblems)\n",
35 | "- algorithm uses the concept of $k-path$\n",
36 | " - $k-path$ from vertex $u$ to $v$ is defined to be any path whose intermediate vertices (aside $u$ and $v$) all have indices less than $k$\n",
37 | " - $0-path$ is defined to be a direct edge from $u$ to $v$\n",
38 | "- following figure illustrates the concept of $k-path$\n",
39 | "
\n",
40 | "- path **1 -> 3** is a **0-path** by definition\n",
41 | "- path **3 -> 0 -> 2** is NOT a **0-path**, but a **1-path** (as well as a **2-path**, a **3-path**, and a **4-path**)\n",
42 | "- path **1 -> 3 -> 2** is a **4-path**\n",
43 | "- all paths in the graph are **4-paths**\n",
44 | "\n",
45 | "### Floyd's algorithm steps:\n",
46 | "- define $D_k(u, v)$ - the length of the shortest *k-path* from vertex $u$ to $v$\n",
47 | " - assume that we already know the shortest *k-path* from $u$ to $v$\n",
48 | "- the shortest *(k+1)-path* either goes through vertex $k$ or it does not\n",
49 | " - if it does go through $k$, the best path is the best *k-path* from $u$ to $k$ followed by the best *k-path* from $k$ to $v$\n",
50 | " - otherwise, keep the best *k-path* seen before\n",
51 | "\n",
52 | "- Floyd's algorithm simply checks all of the possibilities in a triple loop"
53 | ]
54 | },
55 | {
56 | "cell_type": "code",
57 | "execution_count": 1,
58 | "metadata": {},
59 | "outputs": [],
60 | "source": [
61 | "#include \n",
62 | "#include \n",
63 | "#include // sizes of integral types INT_MAX\n",
64 | "#include \n",
65 | "#include \n",
66 | "\n",
67 | "using namespace std;"
68 | ]
69 | },
70 | {
71 | "cell_type": "code",
72 | "execution_count": 2,
73 | "metadata": {},
74 | "outputs": [],
75 | "source": [
76 | "// 2D vector D stores all-pairs shortest paths\n",
77 | "template\n",
78 | "void Floyd(T & G, vector > & D) {\n",
79 | " // initialize D[u][v] with weights(u, v)\n",
80 | " for(int u=0; u(G.V, INT_MAX));\n",
82 | " for(int v=0; vv pairs\n",
86 | " for(int u=0; u (D[u][k] + D[k][v])))\n",
90 | " D[u][v] = D[u][k]+D[k][v];\n",
91 | "}"
92 | ]
93 | },
94 | {
95 | "cell_type": "markdown",
96 | "metadata": {},
97 | "source": [
98 | "### Representing graph using adjacency matrix"
99 | ]
100 | },
101 | {
102 | "cell_type": "code",
103 | "execution_count": 3,
104 | "metadata": {},
105 | "outputs": [],
106 | "source": [
107 | "struct Graph {\n",
108 | " vector > graph;\n",
109 | " size_t V; //no. of vertices\n",
110 | " \n",
111 | " Graph(size_t v) {\n",
112 | " V = v;\n",
113 | " for (int i=0; i row(V, INT_MAX);\n",
116 | " graph.push_back(row);\n",
117 | " for (int j=0; j"
140 | ]
141 | },
142 | {
143 | "cell_type": "code",
144 | "execution_count": 4,
145 | "metadata": {},
146 | "outputs": [],
147 | "source": [
148 | "// represent undirected graph shown in above diagram\n",
149 | "// A->0, B->1, C->2, D->3, E->4\n",
150 | "Graph graph(5);\n",
151 | "vector > dist;"
152 | ]
153 | },
154 | {
155 | "cell_type": "code",
156 | "execution_count": 5,
157 | "metadata": {},
158 | "outputs": [],
159 | "source": [
160 | "graph.addEdge(0, 1, 10);\n",
161 | "graph.addEdge(0, 3, 20);\n",
162 | "graph.addEdge(0, 2, 3);\n",
163 | "graph.addEdge(1, 3, 5);\n",
164 | "graph.addEdge(2, 1, 2);\n",
165 | "graph.addEdge(2, 4, 15);\n",
166 | "graph.addEdge(3, 4, 11);"
167 | ]
168 | },
169 | {
170 | "cell_type": "code",
171 | "execution_count": 6,
172 | "metadata": {},
173 | "outputs": [],
174 | "source": [
175 | "Floyd(graph, dist);"
176 | ]
177 | },
178 | {
179 | "cell_type": "code",
180 | "execution_count": 7,
181 | "metadata": {},
182 | "outputs": [],
183 | "source": [
184 | "void printDistances(Graph & G, vector >&D) {\n",
185 | " int w = 8;\n",
186 | " cout << \"Distance Matrix: \" << endl;\n",
187 | " for (int u=0; u\n",
24 | "Fig. 1 DAG\n",
25 | "- an acceptable topological sort for Figure 1 graph is: J1, J2, J3, J4, J6, J5, J7"
26 | ]
27 | },
28 | {
29 | "cell_type": "markdown",
30 | "metadata": {},
31 | "source": [
32 | "## Depth-first Solution; stack-based\n",
33 | "- a topo sort can be found by performing a DFS on the graph\n",
34 | "- algorithm steps:\n",
35 | " - when a vertex is visited, no action is taken (i.e., function PreVisit does nothing)\n",
36 | " - when the recursion pops back to that vertex, function PostVisit prints the vertex\n",
37 | " - yields a topological sort in reverse order \n",
38 | " - use stack to put it back in the right order\n",
39 | " - it doesn't not matter where the sort starts, as long as all the vertices are visited in the end\n",
40 | "- visualize it here: https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/GraphTopsort.html"
41 | ]
42 | },
43 | {
44 | "cell_type": "code",
45 | "execution_count": 1,
46 | "metadata": {},
47 | "outputs": [],
48 | "source": [
49 | "// we'll use unordered_map to represent graph\n",
50 | "// allows us to store node with any data type without creating/using graph ADT\n",
51 | "#include \n",
52 | "#include \n",
53 | "#include \n",
54 | "#include \n",
55 | "#include \n",
56 | "#include \n",
57 | "#include \n",
58 | "using namespace std;"
59 | ]
60 | },
61 | {
62 | "cell_type": "code",
63 | "execution_count": 2,
64 | "metadata": {},
65 | "outputs": [],
66 | "source": [
67 | "// operator<< overloaded to print a vector\n",
68 | "template\n",
69 | "ostream& operator<<(ostream& out, const vector& v) {\n",
70 | " char comma[3] = {'\\0', ' ', '\\0'};\n",
71 | " out << '[';\n",
72 | " for (auto& e: v) {\n",
73 | " out << comma << e;\n",
74 | " comma[0] = ',';\n",
75 | " }\n",
76 | " out << \"]\\n\";\n",
77 | " return out;\n",
78 | "}"
79 | ]
80 | },
81 | {
82 | "cell_type": "code",
83 | "execution_count": 3,
84 | "metadata": {},
85 | "outputs": [],
86 | "source": [
87 | "// operator<< overloaded to print a unordered_map container\n",
88 | "template\n",
89 | "ostream& operator<<(ostream& out, const unordered_map& m) {\n",
90 | " //char comma[3] = {'\\0', ' ', '\\0'};\n",
91 | " out << \"{\\n\";\n",
92 | " for (auto& e: m) {\n",
93 | " out << \" \" << e.first << ':' << e.second;\n",
94 | " //comma[0] = ',';\n",
95 | " }\n",
96 | " out << \"}\\n\";\n",
97 | " return out;\n",
98 | "}"
99 | ]
100 | },
101 | {
102 | "cell_type": "code",
103 | "execution_count": 4,
104 | "metadata": {},
105 | "outputs": [],
106 | "source": [
107 | "// Lets generate the above graph using unordered_map\n",
108 | "// key is the node and and vector of value is its neighbors\n",
109 | "// Creates out-degree based graph; adjacency-list\n",
110 | "using Graph = unordered_map >;\n",
111 | "Graph DAG;"
112 | ]
113 | },
114 | {
115 | "cell_type": "code",
116 | "execution_count": 5,
117 | "metadata": {},
118 | "outputs": [],
119 | "source": [
120 | "DAG.insert(make_pair(\"J1\", vector{\"J2\", \"J3\"}));\n",
121 | "DAG.insert(make_pair(\"J2\", vector{\"J6\", \"J4\"}));\n",
122 | "DAG.insert(make_pair(\"J3\", vector{\"J4\"}));\n",
123 | "DAG.insert(make_pair(\"J4\", vector{\"J5\"}));\n",
124 | "DAG.insert(make_pair(\"J5\", vector{\"J7\"}));\n",
125 | "DAG.insert(make_pair(\"J6\", vector()));\n",
126 | "DAG.insert(make_pair(\"J7\", vector()));\n",
127 | "DAG[\"J2\"].push_back(\"J5\");"
128 | ]
129 | },
130 | {
131 | "cell_type": "code",
132 | "execution_count": 6,
133 | "metadata": {},
134 | "outputs": [
135 | {
136 | "name": "stdout",
137 | "output_type": "stream",
138 | "text": [
139 | "total nodes of DAG = 7\n"
140 | ]
141 | }
142 | ],
143 | "source": [
144 | "// lets check properties of the graph\n",
145 | "cout << \"total nodes of DAG = \" << DAG.size() << endl;"
146 | ]
147 | },
148 | {
149 | "cell_type": "code",
150 | "execution_count": 7,
151 | "metadata": {},
152 | "outputs": [
153 | {
154 | "name": "stdout",
155 | "output_type": "stream",
156 | "text": [
157 | "total neigbors of J2 = 3\n"
158 | ]
159 | }
160 | ],
161 | "source": [
162 | "// print the no. of neighbors of J2\n",
163 | "cout << \"total neigbors of J2 = \" << DAG[\"J2\"].size() << endl;"
164 | ]
165 | },
166 | {
167 | "cell_type": "code",
168 | "execution_count": 8,
169 | "metadata": {},
170 | "outputs": [
171 | {
172 | "name": "stdout",
173 | "output_type": "stream",
174 | "text": [
175 | "{\n",
176 | " J6:[]\n",
177 | " J4:[J5]\n",
178 | " J1:[J2, J3]\n",
179 | " J5:[J7]\n",
180 | " J3:[J4]\n",
181 | " J7:[]\n",
182 | " J2:[J6, J4, J5]\n",
183 | "}\n"
184 | ]
185 | }
186 | ],
187 | "source": [
188 | "// print the whole DAG\n",
189 | "cout << DAG;"
190 | ]
191 | },
192 | {
193 | "cell_type": "code",
194 | "execution_count": 9,
195 | "metadata": {},
196 | "outputs": [],
197 | "source": [
198 | "unordered_map visited;\n",
199 | "for(auto pair: DAG) {\n",
200 | " visited[pair.first] = false;\n",
201 | "}"
202 | ]
203 | },
204 | {
205 | "cell_type": "code",
206 | "execution_count": 10,
207 | "metadata": {},
208 | "outputs": [],
209 | "source": [
210 | "// answer stack stores the topological order of the nodes\n",
211 | "void DFS(Graph& G, unordered_map& visited, string node, stack& answer) {\n",
212 | " // mark node as visited\n",
213 | " visited[node] = true;\n",
214 | " // run DFS on all its neighbors\n",
215 | " for (auto& neighbor: G[node]) {\n",
216 | " if (!visited[neighbor]) {\n",
217 | " DFS(G, visited, neighbor, answer);\n",
218 | " }\n",
219 | " }\n",
220 | " // visit/print node\n",
221 | " answer.push(node);\n",
222 | "}"
223 | ]
224 | },
225 | {
226 | "cell_type": "code",
227 | "execution_count": 11,
228 | "metadata": {},
229 | "outputs": [],
230 | "source": [
231 | "// depth-first topological sort\n",
232 | "void TopologicalSort(Graph& G, stack& answer) {\n",
233 | " // visited unordered_map, \n",
234 | " unordered_map visited;\n",
235 | " // mark each node as not visited\n",
236 | " for(auto& pair: G) {\n",
237 | " visited[pair.first] = false;\n",
238 | " }\n",
239 | " // run DFS from each node if that node is not visited\n",
240 | " for(auto& pair: G) {\n",
241 | " if (!visited[pair.first]) {\n",
242 | " DFS(G, visited, pair.first, answer);\n",
243 | " }\n",
244 | " }\n",
245 | "}"
246 | ]
247 | },
248 | {
249 | "cell_type": "code",
250 | "execution_count": 12,
251 | "metadata": {},
252 | "outputs": [],
253 | "source": [
254 | "stack answer;"
255 | ]
256 | },
257 | {
258 | "cell_type": "code",
259 | "execution_count": 13,
260 | "metadata": {},
261 | "outputs": [],
262 | "source": [
263 | "// run topological sort or DAG\n",
264 | "TopologicalSort(DAG, answer);"
265 | ]
266 | },
267 | {
268 | "cell_type": "code",
269 | "execution_count": 14,
270 | "metadata": {},
271 | "outputs": [
272 | {
273 | "name": "stdout",
274 | "output_type": "stream",
275 | "text": [
276 | "J1 J3 J2 J4 J5 J7 J6 "
277 | ]
278 | }
279 | ],
280 | "source": [
281 | "// print the topological sort from answer stack\n",
282 | "while(!answer.empty()) {\n",
283 | " cout << answer.top() << \" \";\n",
284 | " answer.pop();\n",
285 | "}"
286 | ]
287 | },
288 | {
289 | "cell_type": "markdown",
290 | "metadata": {},
291 | "source": [
292 | "## Queue-based Solution - Kahn's Algorithm\n",
293 | "- in-degree-based solution\n",
294 | "- https://en.wikipedia.org/wiki/Topological_sorting\n",
295 | "- See https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/GraphTopsort.html\n",
296 | "\n",
297 | "### Algorithm Steps\n",
298 | "1. compute in-degree (number of incoming edges/prerequisites) for each vertex\n",
299 | "2. Place vertices with no prerequisitis or in-degrees of 0 into a queue\n",
300 | "3. While queue is not empty:\n",
301 | " 1. pop the next vertex, v from the queue; and print it\n",
302 | " - decrese in-degree of v's neighbors (i.e. all vertices that hav v as a prerequisite) by 1\n",
303 | " - if in-degree of the neighbor becomes 0, add it to the queue\n",
304 | "4. If the count of printed/visited nodes is NOT equal to the number of nodes, graph contains cycle or topological sort not possible\n",
305 | "\n",
306 | "## E.g., let's work on the above DAG in Fig. 1"
307 | ]
308 | },
309 | {
310 | "cell_type": "code",
311 | "execution_count": 15,
312 | "metadata": {
313 | "code_folding": []
314 | },
315 | "outputs": [],
316 | "source": [
317 | "void KahnsAlgorithm(Graph &G, vector &answer) {\n",
318 | " // step 1: computer in-degree\n",
319 | " // this can be done when building graph for efficiency!\n",
320 | " unordered_map indegree;\n",
321 | " for (auto &pair: G)\n",
322 | " indegree[pair.first] = 0; // initialize in-degree of each v to 0\n",
323 | " \n",
324 | " for (auto &pair: G) {\n",
325 | " for (auto neighbor: G[pair.first]) // for each neighbor of v\n",
326 | " indegree[neighbor] += 1;\n",
327 | " }\n",
328 | " \n",
329 | " // step 2: create a queue of all vertices with 0-indegree\n",
330 | " queue tasksQ;\n",
331 | " for(auto & pair: indegree) {\n",
332 | " if (indegree[pair.first] == 0)\n",
333 | " tasksQ.push(pair.first);\n",
334 | " }\n",
335 | " \n",
336 | " // step 3:\n",
337 | " while(!tasksQ.empty()) {\n",
338 | " string v = tasksQ.front(); // access the first element\n",
339 | " tasksQ.pop(); // remove the first element; step 3.A\n",
340 | " answer.push_back(v);\n",
341 | " // 3.B\n",
342 | " for(auto n: G[v]) {\n",
343 | " --indegree[n];\n",
344 | " // 3.C\n",
345 | " if (indegree[n] == 0)\n",
346 | " tasksQ.push(n);\n",
347 | " }\n",
348 | " }\n",
349 | " // step 4\n",
350 | " //cout << \"answer-size = \" << answer.size() << endl;\n",
351 | " if (answer.size() != G.size())\n",
352 | " {\n",
353 | " // topological sort not possible\n",
354 | " answer.clear();\n",
355 | " answer.push_back(\"topological sort not possible!\");\n",
356 | " }\n",
357 | "}"
358 | ]
359 | },
360 | {
361 | "cell_type": "code",
362 | "execution_count": 16,
363 | "metadata": {},
364 | "outputs": [],
365 | "source": [
366 | "// let's test the KahnsAlgorithm\n",
367 | "vector ans;"
368 | ]
369 | },
370 | {
371 | "cell_type": "code",
372 | "execution_count": 17,
373 | "metadata": {},
374 | "outputs": [
375 | {
376 | "name": "stdout",
377 | "output_type": "stream",
378 | "text": [
379 | "[J1, J2, J3, J6, J4, J5, J7]\n"
380 | ]
381 | }
382 | ],
383 | "source": [
384 | "KahnsAlgorithm(DAG, ans);\n",
385 | "cout << ans;"
386 | ]
387 | },
388 | {
389 | "cell_type": "markdown",
390 | "metadata": {},
391 | "source": [
392 | "## Exercises\n",
393 | "1. Brexit - https://open.kattis.com/problems/brexit\n",
394 | "- Build Dependencies - https://open.kattis.com/problems/builddeps\n",
395 | "- Running MoM - https://open.kattis.com/problems/runningmom\n",
396 | " - finding cycle in a DAG\n",
397 | "- Conservation - https://open.kattis.com/problems/conservation\n",
398 | " - Hints: Keep two queues; one for each lab\n",
399 | " - Run Topoligical sort twice one starting from lab1 and another from lab2\n",
400 | " - use the min answer\n",
401 | " \n",
402 | "- Managin Package - https://open.kattis.com/problems/managingpackaging\n",
403 | " - Hints: Create in-degree/dependency graphs\n",
404 | " - Use queue-based topoligical sort; replace queue with priority queue to print in sorted order"
405 | ]
406 | },
407 | {
408 | "cell_type": "code",
409 | "execution_count": null,
410 | "metadata": {},
411 | "outputs": [],
412 | "source": []
413 | }
414 | ],
415 | "metadata": {
416 | "kernelspec": {
417 | "display_name": "C++14",
418 | "language": "C++14",
419 | "name": "xcpp14"
420 | },
421 | "language_info": {
422 | "codemirror_mode": "text/x-c++src",
423 | "file_extension": ".cpp",
424 | "mimetype": "text/x-c++src",
425 | "name": "c++",
426 | "version": "14"
427 | }
428 | },
429 | "nbformat": 4,
430 | "nbformat_minor": 2
431 | }
432 |
--------------------------------------------------------------------------------
/GeneralTreesUnionFind.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# General Trees & Union/Find Problem\n",
8 | "https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/GenTreeIntro.html\n",
9 | "\n",
10 | "## Table of Contents\n",
11 | "- **[General Trees](#intro)**
\n",
12 | "- **[Union/Find Problem](#union)**
\n",
13 | "- **[Parent Pointer Trees](#ppt)**
\n",
14 | "- **[Parent Pointer Trees Implementation](#pptimp)**
"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | ""
22 | ]
23 | },
24 | {
25 | "cell_type": "markdown",
26 | "metadata": {},
27 | "source": [
28 | "## General Trees\n",
29 | "- many organizations are hierarchical in nature\n",
30 | " - military, most businesses, governments, etc.\n",
31 | "- binary tree is not adequate to represent organizations that have many many subordinates at lower level\n",
32 | "- to represent these hierarchy of many arbitrary number of children, we use general trees\n",
33 | "- general trees are trees whose internal nodes have no fixed number of children\n",
34 | "- the following figure depicts a general tree\n",
35 | "
\n",
36 | "\n",
37 | "### General Tree Definitions and Terminology\n",
38 | "- a tree, $T$ is a finite set of one or more nodes with one special node $R$, the root\n",
39 | "- tree may have many **subtrees** rooted at some nodes that are children of $R$\n",
40 | " - subtrees are arranged from left to right\n",
41 | "- a node's **out degree** is the number of children for that node\n",
42 | "- a **forest** is a collection of one or more trees\n",
43 | "- each node (except for root) has precisely one parent\n",
44 | " - a tree with $n$ nodes must have $n-1$ edges because each node, except the root, has one edge connecting that node to its parent\n",
45 | " \n",
46 | "## Implementation\n",
47 | "- implementation of general tree is much harder compared to binary tree and is ignored"
48 | ]
49 | },
50 | {
51 | "cell_type": "markdown",
52 | "metadata": {},
53 | "source": [
54 | ""
55 | ]
56 | },
57 | {
58 | "cell_type": "markdown",
59 | "metadata": {},
60 | "source": [
61 | "## The Union/Find Problem\n",
62 | "https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/UnionFind.html\n",
63 | "\n",
64 | "### Find: - determine if two objects are in the same set\n",
65 | " - MST: given two nodes, are they in the same tree?\n",
66 | " \n",
67 | "### Union: efficiently merge two sets into one\n",
68 | " - MST: merge two disjoint trees into one\n",
69 | " \n",
70 | "- Kruskal's minimum spanning tree (MST) uses Union/Find technique\n",
71 | "- what data structure can efficiently implement Union/Find operations?"
72 | ]
73 | },
74 | {
75 | "cell_type": "markdown",
76 | "metadata": {},
77 | "source": [
78 | ""
79 | ]
80 | },
81 | {
82 | "cell_type": "markdown",
83 | "metadata": {},
84 | "source": [
85 | "## Parent Pointer Trees\n",
86 | "- a simple way to represent general tree \n",
87 | " - for each node store only a pointer to that node's parent\n",
88 | " - called **parent pointer representation**\n",
89 | "- helps us precisely solve the Union/Find problem by offering two basic operations:\n",
90 | " 1. determine if two objects are in the same set ( the **FIND** operation)\n",
91 | " - follow the series of parent pointers from each node to its respective root\n",
92 | " - if both nodes have same root they belong to the same tree\n",
93 | " - helps if the height of the trees are shorter (or shortest possible)\n",
94 | " \n",
95 | " 2. merge two disjoints sets together (intersection of disjoint sets is empty)\n",
96 | " - disjoint sets are united (the **UNION** operation)\n",
97 | " - perhaps by making one the parent of the other\n",
98 | " - goal is to keep the height shorter when merging\n",
99 | "- this 2-step process goes by the name **UNION/FIND**"
100 | ]
101 | },
102 | {
103 | "cell_type": "markdown",
104 | "metadata": {},
105 | "source": [
106 | ""
107 | ]
108 | },
109 | {
110 | "cell_type": "markdown",
111 | "metadata": {},
112 | "source": [
113 | "## Parent Pointer Tree Implementation\n",
114 | "- represented using a single array\n",
115 | "- index represents node and the element stored represents its parent\n",
116 | " - a single array is used to implement a collection of trees\n",
117 | "- use path compression and weighted union techniques \n",
118 | " - keep the height of the joined tree to as short as possible\n",
119 | "
"
120 | ]
121 | },
122 | {
123 | "cell_type": "code",
124 | "execution_count": 1,
125 | "metadata": {},
126 | "outputs": [],
127 | "source": [
128 | "// a simplified demonstration of parent pointer tree\n",
129 | "#include \n",
130 | "#include \n",
131 | "\n",
132 | "using namespace std;"
133 | ]
134 | },
135 | {
136 | "cell_type": "code",
137 | "execution_count": 2,
138 | "metadata": {},
139 | "outputs": [],
140 | "source": [
141 | "// represent the above tree using parent pointer implementation\n",
142 | "vector parent(10, -1); //initialize parent vector of 10 nodes with -1\n",
143 | "// can also initialize parent of a node at index i to itself"
144 | ]
145 | },
146 | {
147 | "cell_type": "code",
148 | "execution_count": 3,
149 | "metadata": {},
150 | "outputs": [
151 | {
152 | "data": {
153 | "text/plain": [
154 | "5"
155 | ]
156 | },
157 | "execution_count": 3,
158 | "metadata": {},
159 | "output_type": "execute_result"
160 | }
161 | ],
162 | "source": [
163 | "parent[0] = 5;\n",
164 | "parent[1] = 0;\n",
165 | "parent[2] = 0;\n",
166 | "parent[3] = 5;\n",
167 | "parent[4] = 3;\n",
168 | "//parent[5] = -1;\n",
169 | "parent[6] = 5;\n",
170 | "parent[7] = 2;\n",
171 | "parent[8] = 5;\n",
172 | "// parent[9] = -1"
173 | ]
174 | },
175 | {
176 | "cell_type": "code",
177 | "execution_count": 4,
178 | "metadata": {},
179 | "outputs": [],
180 | "source": [
181 | "// recursive function to print path in reverse order from node to its root\n",
182 | "void printPathReverse(vector &parent, int node) {\n",
183 | " cout << char(node+65) << \" \";\n",
184 | " if (parent[node] == -1) return;\n",
185 | " printPathReverse(parent, parent[node]);\n",
186 | "}"
187 | ]
188 | },
189 | {
190 | "cell_type": "code",
191 | "execution_count": 5,
192 | "metadata": {},
193 | "outputs": [
194 | {
195 | "name": "stdout",
196 | "output_type": "stream",
197 | "text": [
198 | "H C A F "
199 | ]
200 | }
201 | ],
202 | "source": [
203 | "// print path to H\n",
204 | "printPathReverse(parent, 7);"
205 | ]
206 | },
207 | {
208 | "cell_type": "code",
209 | "execution_count": 6,
210 | "metadata": {},
211 | "outputs": [],
212 | "source": [
213 | "// recursive function to print path in from root to the given node\n",
214 | "void printPath(vector &parent, int node) {\n",
215 | " if (node == -1) return;\n",
216 | " printPath(parent, parent[node]);\n",
217 | " cout << char(node+65) << \" \";\n",
218 | "}"
219 | ]
220 | },
221 | {
222 | "cell_type": "code",
223 | "execution_count": 7,
224 | "metadata": {},
225 | "outputs": [
226 | {
227 | "name": "stdout",
228 | "output_type": "stream",
229 | "text": [
230 | "F A C H "
231 | ]
232 | }
233 | ],
234 | "source": [
235 | "// print path from root to to H\n",
236 | "printPath(parent, 7);"
237 | ]
238 | },
239 | {
240 | "cell_type": "code",
241 | "execution_count": 8,
242 | "metadata": {},
243 | "outputs": [],
244 | "source": [
245 | "// recursively find root without compressing path\n",
246 | "int find(vector &parent, int node) {\n",
247 | " if (parent[node] == -1) return node;\n",
248 | " return find(parent, parent[node]);\n",
249 | "}"
250 | ]
251 | },
252 | {
253 | "cell_type": "code",
254 | "execution_count": 9,
255 | "metadata": {},
256 | "outputs": [
257 | {
258 | "name": "stdout",
259 | "output_type": "stream",
260 | "text": [
261 | "F"
262 | ]
263 | }
264 | ],
265 | "source": [
266 | "// find root of H\n",
267 | "cout << char(find(parent, 7)+65);"
268 | ]
269 | },
270 | {
271 | "cell_type": "code",
272 | "execution_count": 10,
273 | "metadata": {},
274 | "outputs": [
275 | {
276 | "name": "stdout",
277 | "output_type": "stream",
278 | "text": [
279 | "A\n",
280 | "F\n"
281 | ]
282 | },
283 | {
284 | "data": {
285 | "text/plain": [
286 | "@0x10b9f7010"
287 | ]
288 | },
289 | "execution_count": 10,
290 | "metadata": {},
291 | "output_type": "execute_result"
292 | }
293 | ],
294 | "source": [
295 | "// check parents of all the nodes in path to H;\n",
296 | "// still the same as path has not been compressed\n",
297 | "cout << char(parent[2]+65) << endl; // C\n",
298 | "cout << char(parent[0]+65) << endl; // A"
299 | ]
300 | },
301 | {
302 | "cell_type": "markdown",
303 | "metadata": {},
304 | "source": [
305 | "## Do nodes J and H belong to the same tree?"
306 | ]
307 | },
308 | {
309 | "cell_type": "code",
310 | "execution_count": 11,
311 | "metadata": {},
312 | "outputs": [
313 | {
314 | "name": "stdout",
315 | "output_type": "stream",
316 | "text": [
317 | "F J\n"
318 | ]
319 | }
320 | ],
321 | "source": [
322 | "// find root of J and H\n",
323 | "cout << char(find(parent, 7)+65) << \" \" << char(find(parent, 9)+65) << endl;"
324 | ]
325 | },
326 | {
327 | "cell_type": "code",
328 | "execution_count": 12,
329 | "metadata": {},
330 | "outputs": [
331 | {
332 | "name": "stdout",
333 | "output_type": "stream",
334 | "text": [
335 | "No they do not belong to the same tree!"
336 | ]
337 | }
338 | ],
339 | "source": [
340 | "if (find(parent, 9) == find(parent, 7))\n",
341 | " cout << \"Yes they belong to the same tree!\";\n",
342 | "else\n",
343 | " cout << \"No they do not belong to the same tree!\";"
344 | ]
345 | },
346 | {
347 | "cell_type": "markdown",
348 | "metadata": {},
349 | "source": [
350 | "## Path Compression\n",
351 | "- path compression technique can be used to create extremely shallow trees\n",
352 | "- resets the parent of every node on the path from say $X$ to $R$ to $R$\n",
353 | "- keeps the cost of subsequent FIND operations very close to constant\n",
354 | " - O(log$n$) in the worst case"
355 | ]
356 | },
357 | {
358 | "cell_type": "code",
359 | "execution_count": 13,
360 | "metadata": {},
361 | "outputs": [],
362 | "source": [
363 | "// find root of node by compressing the path\n",
364 | "// all the nodes in path to node will have their root changed to the root of \n",
365 | "int findCompression(vector &parent, int node) {\n",
366 | " if (parent[node] == -1) return node;\n",
367 | " parent[node] = findCompression(parent, parent[node]);\n",
368 | " return parent[node];\n",
369 | "}"
370 | ]
371 | },
372 | {
373 | "cell_type": "code",
374 | "execution_count": 14,
375 | "metadata": {},
376 | "outputs": [
377 | {
378 | "name": "stdout",
379 | "output_type": "stream",
380 | "text": [
381 | "F"
382 | ]
383 | }
384 | ],
385 | "source": [
386 | "// find root of H and compress path\n",
387 | "cout << char(findCompression(parent, 7)+65);"
388 | ]
389 | },
390 | {
391 | "cell_type": "code",
392 | "execution_count": 15,
393 | "metadata": {},
394 | "outputs": [
395 | {
396 | "name": "stdout",
397 | "output_type": "stream",
398 | "text": [
399 | "F\n"
400 | ]
401 | }
402 | ],
403 | "source": [
404 | "// check parent of H\n",
405 | "cout << char(parent[7]+65) << endl;"
406 | ]
407 | },
408 | {
409 | "cell_type": "code",
410 | "execution_count": 16,
411 | "metadata": {},
412 | "outputs": [
413 | {
414 | "name": "stdout",
415 | "output_type": "stream",
416 | "text": [
417 | "F\n",
418 | "F\n"
419 | ]
420 | },
421 | {
422 | "data": {
423 | "text/plain": [
424 | "@0x10b9f7010"
425 | ]
426 | },
427 | "execution_count": 16,
428 | "metadata": {},
429 | "output_type": "execute_result"
430 | }
431 | ],
432 | "source": [
433 | "// check parent of all the nodes in path to H\n",
434 | "// path should be compressed making C and A's parents same as H's parents\n",
435 | "cout << char(parent[2]+65) << endl; // 2->C\n",
436 | "cout << char(parent[0]+65) << endl; // 0->A"
437 | ]
438 | },
439 | {
440 | "cell_type": "markdown",
441 | "metadata": {},
442 | "source": [
443 | "## Weighted Union\n",
444 | "- technique to join two sets by reducing their height\n",
445 | " - limits the total depth of the tree to $O(logn)$\n",
446 | "- joins the tree with fewer nodes to the tree with more nodes\n",
447 | " - make the smaller tree's root point to the root of the bigger tree\n",
448 | "- visualize weighted union here:https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/UnionFind.html"
449 | ]
450 | },
451 | {
452 | "cell_type": "markdown",
453 | "metadata": {},
454 | "source": [
455 | "### parent pointer tree implementation as ADT"
456 | ]
457 | },
458 | {
459 | "cell_type": "code",
460 | "execution_count": 17,
461 | "metadata": {},
462 | "outputs": [],
463 | "source": [
464 | "#include \n",
465 | "#include \n",
466 | "#include \n",
467 | "#include \n",
468 | "#include \n",
469 | "#include \n",
470 | "using namespace std;"
471 | ]
472 | },
473 | {
474 | "cell_type": "code",
475 | "execution_count": 18,
476 | "metadata": {},
477 | "outputs": [],
478 | "source": [
479 | "// general Parent-Pointer Tree implementation for UNION/FIND\n",
480 | "class ParPtrTree {\n",
481 | " private:\n",
482 | " vector parents; // parent pointer vector\n",
483 | " vector weights; // weights for weighted union\n",
484 | " public:\n",
485 | " // constructor\n",
486 | " ParPtrTree(size_t size) {\n",
487 | " parents.resize(size); //create parents vector\n",
488 | " fill(parents.begin(), parents.end(), -1); // each node is its own root to start\n",
489 | " weights.resize(size); \n",
490 | " fill(weights.begin(), weights.end(), 1);// set all base weights to 1\n",
491 | " }\n",
492 | " \n",
493 | " // Return the root of a given node with path compression\n",
494 | " // recursive algorithm that makes all ancestors of the current node\n",
495 | " // point to the root\n",
496 | " int FIND(int node) {\n",
497 | " if (parents[node] == -1) return node;\n",
498 | " parents[node] = FIND(parents[node]);\n",
499 | " return parents[node];\n",
500 | " }\n",
501 | " \n",
502 | " // Merge two subtrees if they are different\n",
503 | " void UNION(int node1, int node2) {\n",
504 | " int root1 = FIND(node1);\n",
505 | " int root2 = FIND(node2);\n",
506 | " // MERGE two trees\n",
507 | " if (root1 != root2) {\n",
508 | " // if weight of root1 is smaller; \n",
509 | " // root1 will point to root2\n",
510 | " if (weights[root1] < weights[root2]) {\n",
511 | " parents[root1] = root2;\n",
512 | " weights[root2] += weights[root1];\n",
513 | " }\n",
514 | " // root2 will point to root1\n",
515 | " else {\n",
516 | " parents[root2] = root1;\n",
517 | " weights[root1] += weights[root2];\n",
518 | " }\n",
519 | " } \n",
520 | " }\n",
521 | " \n",
522 | " // print representation of ParentPtrTree;\n",
523 | " // assuming nodes are A, B, C... as shown in the figure\n",
524 | " void print() {\n",
525 | " int w = 5, w1= 15;\n",
526 | " cout << setw(w1) << \"parent nodes:\";\n",
527 | " for (int i=0; i < this->parents.size(); i++) {\n",
528 | " if (parents[i] == -1)\n",
529 | " cout << setw(w) << \"/\";\n",
530 | " else\n",
531 | " cout << setw(w) << char(this->parents[i]+65);\n",
532 | " }\n",
533 | " cout << '\\n' << setw(w1) << \"parent ids:\";\n",
534 | " for (int i=0; i < this->parents.size(); i++) {\n",
535 | " cout << setw(w) << this->parents[i];\n",
536 | " }\n",
537 | " cout << '\\n' << setw(w1) << \"node ids:\";\n",
538 | " for (int i=0; i < this->parents.size(); i++) {\n",
539 | " cout << setw(w) << i;\n",
540 | " }\n",
541 | " }\n",
542 | "};"
543 | ]
544 | },
545 | {
546 | "cell_type": "markdown",
547 | "metadata": {},
548 | "source": [
549 | "### Test ParPtrTree\n",
550 | "- the following test code can be modified to test examples provided here: \n",
551 | "https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/UnionFind.html"
552 | ]
553 | },
554 | {
555 | "cell_type": "code",
556 | "execution_count": 19,
557 | "metadata": {},
558 | "outputs": [],
559 | "source": [
560 | "// 10 disjoint sets: A-J mapped as 0-9\n",
561 | "// A: 0, B: 1, ... J: 9\n",
562 | "ParPtrTree ptr(10);"
563 | ]
564 | },
565 | {
566 | "cell_type": "code",
567 | "execution_count": 20,
568 | "metadata": {},
569 | "outputs": [
570 | {
571 | "name": "stdout",
572 | "output_type": "stream",
573 | "text": [
574 | " parent nodes: / / / / / / / / / /\n",
575 | " parent ids: -1 -1 -1 -1 -1 -1 -1 -1 -1 -1\n",
576 | " node ids: 0 1 2 3 4 5 6 7 8 9"
577 | ]
578 | }
579 | ],
580 | "source": [
581 | "ptr.print();"
582 | ]
583 | },
584 | {
585 | "cell_type": "code",
586 | "execution_count": 21,
587 | "metadata": {},
588 | "outputs": [
589 | {
590 | "name": "stdout",
591 | "output_type": "stream",
592 | "text": [
593 | " parent nodes: / / / / / / / / / H\n",
594 | " parent ids: -1 -1 -1 -1 -1 -1 -1 -1 -1 7\n",
595 | " node ids: 0 1 2 3 4 5 6 7 8 9"
596 | ]
597 | }
598 | ],
599 | "source": [
600 | "// union nodes (H) and (J)\n",
601 | "ptr.UNION(7, 9);\n",
602 | "ptr.print();"
603 | ]
604 | },
605 | {
606 | "cell_type": "code",
607 | "execution_count": 22,
608 | "metadata": {},
609 | "outputs": [
610 | {
611 | "name": "stdout",
612 | "output_type": "stream",
613 | "text": [
614 | " parent nodes: / / / / / / / / G H\n",
615 | " parent ids: -1 -1 -1 -1 -1 -1 -1 -1 6 7\n",
616 | " node ids: 0 1 2 3 4 5 6 7 8 9"
617 | ]
618 | }
619 | ],
620 | "source": [
621 | "// union nodes (G) and (I)\n",
622 | "ptr.UNION(6, 8);\n",
623 | "ptr.print();"
624 | ]
625 | },
626 | {
627 | "cell_type": "code",
628 | "execution_count": 24,
629 | "metadata": {},
630 | "outputs": [
631 | {
632 | "name": "stdout",
633 | "output_type": "stream",
634 | "text": [
635 | " parent nodes: H / / / / / / / G H\n",
636 | " parent ids: 7 -1 -1 -1 -1 -1 -1 -1 6 7\n",
637 | " node ids: 0 1 2 3 4 5 6 7 8 9"
638 | ]
639 | }
640 | ],
641 | "source": [
642 | "// union nodes (A) and (J)\n",
643 | "ptr.UNION(0, 9);\n",
644 | "ptr.print();"
645 | ]
646 | },
647 | {
648 | "cell_type": "code",
649 | "execution_count": 25,
650 | "metadata": {},
651 | "outputs": [
652 | {
653 | "name": "stdout",
654 | "output_type": "stream",
655 | "text": [
656 | " parent nodes: H H / / / / / / G H\n",
657 | " parent ids: 7 7 -1 -1 -1 -1 -1 -1 6 7\n",
658 | " node ids: 0 1 2 3 4 5 6 7 8 9"
659 | ]
660 | }
661 | ],
662 | "source": [
663 | "ptr.UNION(1, 7);\n",
664 | "ptr.print();"
665 | ]
666 | },
667 | {
668 | "cell_type": "code",
669 | "execution_count": 26,
670 | "metadata": {},
671 | "outputs": [
672 | {
673 | "name": "stdout",
674 | "output_type": "stream",
675 | "text": [
676 | " parent nodes: H H / / / / H / G H\n",
677 | " parent ids: 7 7 -1 -1 -1 -1 7 -1 6 7\n",
678 | " node ids: 0 1 2 3 4 5 6 7 8 9"
679 | ]
680 | }
681 | ],
682 | "source": [
683 | "ptr.UNION(6, 9);\n",
684 | "ptr.print();"
685 | ]
686 | },
687 | {
688 | "cell_type": "markdown",
689 | "metadata": {},
690 | "source": [
691 | "## Exercises\n",
692 | "1. Tildes - https://open.kattis.com/problems/tildes\n",
693 | " - Hint: recursively update weights of intermediate nodes similar to find\n",
694 | "- Union-Find - https://open.kattis.com/problems/unionfind"
695 | ]
696 | },
697 | {
698 | "cell_type": "code",
699 | "execution_count": null,
700 | "metadata": {},
701 | "outputs": [],
702 | "source": []
703 | }
704 | ],
705 | "metadata": {
706 | "kernelspec": {
707 | "display_name": "C++14",
708 | "language": "C++14",
709 | "name": "xcpp14"
710 | },
711 | "language_info": {
712 | "codemirror_mode": "text/x-c++src",
713 | "file_extension": ".cpp",
714 | "mimetype": "text/x-c++src",
715 | "name": "c++",
716 | "version": "14"
717 | }
718 | },
719 | "nbformat": 4,
720 | "nbformat_minor": 2
721 | }
722 |
--------------------------------------------------------------------------------
/GraphsIntro.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Graphs\n",
8 | "https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/GraphIntro.html\n",
9 | "\n",
10 | "## Table of Contents\n",
11 | "- **[Introduction](#intro)**
\n",
12 | "- **[Graph Types](#types)**
\n",
13 | "- **[Graph Representations](#representations)**
\n",
14 | "- **[Adjacency Matrix Vs Adjacency List](#versus)**
"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | ""
22 | ]
23 | },
24 | {
25 | "cell_type": "markdown",
26 | "metadata": {},
27 | "source": [
28 | "## Introduction\n",
29 | "- most flexible and important data structure\n",
30 | "- consists of a set of nodes (vertices), and a set of edges \n",
31 | " - each edge connects two nodes\n",
32 | "- trees and lists can be be viewed as special cases of graphs\n",
33 | "
\n",
34 | "Figure of a graph\n",
35 | "\n",
36 | "## Graphs Vs Trees\n",
37 | "- https://freefeast.info/difference-between/difference-between-trees-and-graphs-trees-vs-graphs/\n",
38 | "- Tree is a restricted form of graph which is minimally connected having only one path between any two vertices\n",
39 | "- Trees have direction (parent/child relationships) without cycles (Directed Acyclic Graph, DAG)\n",
40 | " - a child can have only one parent\n",
41 | "- Graphs can have more than one edges connecting vertices\n",
42 | " - more than one path\n",
43 | " - can have uni-directional or bi-directional paths (edges) between nodes\n",
44 | "\n",
45 | "## Applications\n",
46 | "- used to model both real-world systems and abstract problems, e.g.:\n",
47 | "- modeling connectivity in computer networks\n",
48 | "- representing maps as a set of locations with distances between locations (GPS shortest route finder)\n",
49 | "- modeling flow capacities in transportation networks (finding bottlenecks)\n",
50 | "- modeling a path from a starting condition to a goal condition (used in AI and video games)\n",
51 | "- modeling relationships such as family trees, social networks, scientific taxonomies\n",
52 | "\n",
53 | "## Terminologies\n",
54 | "- **graph** $G = (V, E)$ consists of a set of **vertices** $V$ and a set of **edges** $E$\n",
55 | " - each edge in $E$ is a connection between a pair of vertices in $V$\n",
56 | "- $\\|V\\|$ - number of vertices\n",
57 | "- $\\|E\\|$ - the number of edges \n",
58 | " - $\\|E\\|$ can range from zero to a maximum of $\\|V^2\\| - \\|V\\|$\n",
59 | "- **adjacent** vertices with a direct connection is written $(a, b)$\n",
60 | " - $a$ is adjacent to $b$ and vice-versa\n",
61 | "- **path** - sequence of vertices $v_1, v_2, ..., v_n$ with length $n-1$ if there's path from $v_1$ to $v_n$\n",
62 | "- **simple path** - all vertices on its path are unique\n",
63 | " - in left figure, path 0->1->3 is a simple path\n",
64 | " - in middle figure, the path 0->1->3->2->4->1 is NOT a simple path\n",
65 | "- **length** of a path is the number of edges it contains\n",
66 | " - in left figure, length of the path 0->1->3 is 2\n",
67 | "- **cycle** is a path of length three or more that connects some vertex $v_i$ to itself\n",
68 | " - in the right figure, the path 1->3->2->4->1 is a cycle\n",
69 | "- **simple cycle** - simple path except that the first and last vertices are the same\n",
70 | " - in the right figure, the path 1->3->2->4->1 is a simple cycle\n",
71 | "
\n",
72 | "\n"
73 | ]
74 | },
75 | {
76 | "cell_type": "markdown",
77 | "metadata": {},
78 | "source": [
79 | ""
80 | ]
81 | },
82 | {
83 | "cell_type": "markdown",
84 | "metadata": {},
85 | "source": [
86 | "## Types of Graphs\n",
87 | "
\n",
88 | " \n",
89 | "### Undirected graph\n",
90 | "- graph (a) whose edges are not directed is called undirected graph\n",
91 | "- **degree** the number of edges a node has\n",
92 | " - e.g., the degree of center node in (a) is three\n",
93 | "\n",
94 | "### Directed graph (digraph)\n",
95 | "- graph (b) whose edges are directed from one vertex to another\n",
96 | "- **out degree** of a vertex is the number of edges going out from it\n",
97 | " - in (c) above, out degree of $1$ is one\n",
98 | "- **in degree** of a vertex is the number of edges coming in to it\n",
99 | " - in (c) above, the in degree of vertex $1$ is two\n",
100 | " \n",
101 | "### Weighted graph (labeled graph)\n",
102 | "- graph (c) whose edges have associated weight (cost) or simply some labels\n",
103 | "- weighted graphs can be either directed or undirected\n",
104 | "\n",
105 | "### Connected graph\n",
106 | "- an undirected graph which has at least one path from any vertex to any other\n",
107 | "
\n",
108 | "\n",
109 | "### Sparse graph\n",
110 | "- graph with relatively few edges\n",
111 | "
\n",
112 | "Sparse graph\n",
113 | "\n",
114 | "### Dense graph\n",
115 | "- graph with relatively many edges\n",
116 | "
\n",
117 | "Dense and complete graph\n",
118 | "\n",
119 | "### Complete graph\n",
120 | "- graph with all possible edges (see above figure)\n",
121 | "- no. of edges in a complete graph = $\\frac{\\|V\\|(\\|V\\|-1)}{2}$\n",
122 | "\n",
123 | "### Subgraph\n",
124 | "- a subgraph $G_1$ is part of of a graph $G$ (with vertices and edges appearing exactly as in the the graph $G$\n",
125 | "- e.g., $G_1 = $ nodes $\\{0, 2, 3\\}$ and edges $\\{(0,2), (2,3), (0,3)\\}$\n",
126 | "
\n",
127 | "Subgraph connected with red edges is clique\n",
128 | "\n",
129 | "### Clique\n",
130 | "- a complete subgraph where all vertices are interconnected\n",
131 | "- e.g. the red colored subgraph above\n",
132 | "\n",
133 | "### Acyclic graph\n",
134 | "- graph without cycles\n",
135 | "- e.g. see figure b below\n",
136 | "\n",
137 | "### Directed acyclic graph (DAG)\n",
138 | "- directed graph without cycles\n",
139 | "- e.g. see figure a below\n",
140 | "
\n",
141 | "\n",
142 | "### Free tree\n",
143 | "- connected, undirected graph with no simple cycles\n",
144 | " - connected acyclic graph with $\\|V\\| - 1$ edges\n",
145 | " - e.g., figure (b) acyclic graph above is free tree"
146 | ]
147 | },
148 | {
149 | "cell_type": "markdown",
150 | "metadata": {},
151 | "source": [
152 | ""
153 | ]
154 | },
155 | {
156 | "cell_type": "markdown",
157 | "metadata": {},
158 | "source": [
159 | "## Graph Representations\n",
160 | "- two common methods\n",
161 | "- adjacency matrix and adjacency list\n",
162 | "\n",
163 | "### Adjacency matrix\n",
164 | "- a graph of $\\|V\\| \\times \\|V\\|$ matrix (2-D array)\n",
165 | "- vertices are typically labeled from $0$ through ${\\|V\\|-1}$\n",
166 | "- row $i$ of the matrix contains entries for vertex $v_i$\n",
167 | "- column $j$ in row $i$ is marked if there's an edge from $v_i$ to $v_j$\n",
168 | " - matrix is initialized with $0$s\n",
169 | "- space requirement is $\\Theta(\\|V\\|^2)$\n",
170 | "\n",
171 | "### Adjacency list\n",
172 | "- array/vector of linked lists\n",
173 | "- the length of array is $\\|V\\|$, with index $i$ storing a pointer to the linked list of edges for vertex $v_i$\n",
174 | " - each linked list represents the edges of the vertices that are adjacent to vertex $v_i$\n",
175 | "- space requirement is $\\Theta(\\|V\\|+\\|E\\|)$\n",
176 | " \n",
177 | "### Directed graph representations\n",
178 | "
\n",
179 | "\n",
180 | "### Undirected graph representations\n",
181 | "
\n",
182 | "\n",
183 | "### Weighted graph representations\n",
184 | "- easier with adjacency matrix where the entry is simply the weight\n",
185 | "- weight needs to be explicitly stored in the node of the linked list\n",
186 | "
"
187 | ]
188 | },
189 | {
190 | "cell_type": "markdown",
191 | "metadata": {},
192 | "source": [
193 | ""
194 | ]
195 | },
196 | {
197 | "cell_type": "markdown",
198 | "metadata": {},
199 | "source": [
200 | "## Adjacency Matrix Vs Adjacency List\n",
201 | "- which graph representation is more space efficient depends on the number of edges in the graph\n",
202 | "- adjacency matrix cost $O(\\|V\\|^2)$\n",
203 | "- adjacency list cost $O(\\|V\\|\\times\\|E\\|)$\n",
204 | "- as the graph becomes denser, the adjacency matrix becomes relatively more space efficient\n",
205 | " - storing pointers and extra space for weight can be costly for adjacency list\n",
206 | "- adjacency list is more space efficient when the graph is sparse"
207 | ]
208 | },
209 | {
210 | "cell_type": "markdown",
211 | "metadata": {},
212 | "source": [
213 | "## Exercises\n",
214 | "
\n",
215 | "\n",
216 | "1. What is the degree of vertex $3$ in above graph?\n",
217 | "2. Which of the following correctly describe the graph?\n",
218 | " 1. Connected Graph\n",
219 | " - Dense Graph\n",
220 | " - Directed Graph\n",
221 | " - Acyclic Graph\n",
222 | " - Sparse Graph\n",
223 | " - Complete Graph\n",
224 | " - Undirected Graph\n",
225 | "3. A simple path:\n",
226 | " 1. must have all vertices unique except that the first and last vertices are the same\n",
227 | " - must have all vertices be unique\n",
228 | " - allows repetition of vertices so long as the length of the path is less than 5\n",
229 | " - None of the above\n",
230 | "4. What are different simple paths between vertices $0$ and $4$ in above graph?"
231 | ]
232 | },
233 | {
234 | "cell_type": "code",
235 | "execution_count": null,
236 | "metadata": {},
237 | "outputs": [],
238 | "source": []
239 | }
240 | ],
241 | "metadata": {
242 | "kernelspec": {
243 | "display_name": "C++14",
244 | "language": "C++14",
245 | "name": "xcpp14"
246 | },
247 | "language_info": {
248 | "codemirror_mode": "text/x-c++src",
249 | "file_extension": ".cpp",
250 | "mimetype": "text/x-c++src",
251 | "name": "c++",
252 | "version": "14"
253 | }
254 | },
255 | "nbformat": 4,
256 | "nbformat_minor": 4
257 | }
258 |
--------------------------------------------------------------------------------
/GraphsShortestPaths.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Shortest Paths in Graphs\n",
8 | "https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/GraphShortest.html\n",
9 | "\n",
10 | "### Table of Contents\n",
11 | "- **[Shortest-Paths Problems](#problems)**
\n",
12 | "- **[Single Source Shortest Paths](#sssp)**
\n",
13 | "- **[Dijkstra's Algorithm](#diajkstra)**
"
14 | ]
15 | },
16 | {
17 | "cell_type": "markdown",
18 | "metadata": {},
19 | "source": [
20 | "## Shortest-Path Problems\n",
21 | "- modeling road networks to find shortest path from point A to point B\n",
22 | "- road networks can be modeled as a directed graph whose edges are labeled with real numbers\n",
23 | " - labels may be called weights, costs, or distances\n",
24 | "- a typical problem is to find the total length of the shortest path between two specified vertices\n",
25 | "- see figure below, e.g.:\n",
26 | " - $w = $ weight\n",
27 | " - $d = $ shortest path\n",
28 | " - $w(A, D) = 20$\n",
29 | " - $d(A, D) = 10$\n",
30 | " - $w(E, B) = \\infty$\n",
31 | "- assume that all weights are positive\n",
32 | "\n",
33 | "
"
34 | ]
35 | },
36 | {
37 | "cell_type": "markdown",
38 | "metadata": {},
39 | "source": [
40 | "## Single-Source Shortest Paths (SSSP)\n",
41 | "- given vertex $S$ in Graph $G$, find the shortest paths from $S$ to every other vertex in $G$\n",
42 | "- finding the shortest path from $S$ to $T$ requires us to find the shortest paths from $S$ to every other vertex as well (in the worst case)\n",
43 | "- algorithm presented here computes only the distance to every vertex rather than recording the actual path\n",
44 | "- path can be recorded and printed by remembering parent vertex for each vertex using a vector (left as an exercise)\n",
45 | "\n",
46 | "### Applications\n",
47 | "- find the cheapest way for one computer to broadcast a message to all other computers on a computer network\n",
48 | "- find the fastest route from point A to point B\n",
49 | "- find the cheapest flight from point A to point B\n",
50 | "\n",
51 | "### SSSP for Unweighted Graphs\n",
52 | "- SSSP for unweighted graphs (or all edges with same cost) can be found using a simple breadth-first search\n",
53 | "\n",
54 | "### SSSP for Weighted Graphs\n",
55 | "- use Dijkstra's algorithm\n",
56 | " - assumes weights are positive values"
57 | ]
58 | },
59 | {
60 | "cell_type": "markdown",
61 | "metadata": {},
62 | "source": [
63 | "## Dijkstra's SSSP Algorithm\n",
64 | "https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm\n",
65 | "
\n",
66 | "- given a graph $G = (V, E)$:\n",
67 | "- shortest path from $A$ to $B$: $d(A, B) = min(d(A, U)) + w(U, B)$\n",
68 | " - $d(A, B)$ is the minimum over all paths that go from $A$ to $U$, then have an edge from $U$ to $B$, where $U$ is some vertex in $V$. \n",
69 | "- Diajkstra's algorithm will assign some initial distance values and will try to improve them step by step\n",
70 | "- the technique commonly called \"greedy\"\n",
71 | "\n",
72 | "- algorithms steps:\n",
73 | " 1. create a set of all the **unvisited nodes**\n",
74 | " 2. assign every node a tentative distance value using array: $0$ for start vertex, $\\infty$ for all other nodes\n",
75 | " 3. for each node, consider all of its unvisited neighbors and calculate their tentative distances through the current node, update the distance with the smaller value\n",
76 | " e.g., if the current node $u$ is marked with a distance of $6$ and the edge connecting it with a neighbor $v$ has length $2$, then the distance to $v$ through $u$ is $6+2=8$. If $v$'s current distance is greater than $8$, then update it to $8$\n",
77 | " 4. when done considering all the unvisited neighbors of the current node, mark the current node as visited and remove it from the **unvisited set**\n",
78 | " 5. select the next unvisited node that has the smallest tentative distance, and repeat from step 3\n",
79 | " - at the end, array created in step 2 will contain the shortest distance values \n",
80 | " \n",
81 | "
\n",
82 | "\n",
83 | "### visualize Dijkstra's SSSP algorithm here: https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/GraphShortest.html"
84 | ]
85 | },
86 | {
87 | "cell_type": "code",
88 | "execution_count": null,
89 | "metadata": {},
90 | "outputs": [],
91 | "source": [
92 | "#include \n",
93 | "#include \n",
94 | "#include // priority_queue\n",
95 | "#include // sizes of integral types\n",
96 | "#include // make_pair\n",
97 | "#include \n",
98 | "#include \n",
99 | "\n",
100 | "using namespace std;\n",
101 | "using iPair = pair;"
102 | ]
103 | },
104 | {
105 | "cell_type": "code",
106 | "execution_count": null,
107 | "metadata": {},
108 | "outputs": [],
109 | "source": [
110 | "// Given a graph G, Dijkstra() finds SSSP to all the nodes from given source\n",
111 | "// dist vector will have the shortest distances from the given source\n",
112 | "// when the function terminates\n",
113 | "// function can be modified to find shortest path to a single destination\n",
114 | "// see Single Destination comment below\n",
115 | "// function can also be modified to trace the shortest path using parent vector\n",
116 | "template\n",
117 | "void Dijkstra(T & G, int source, vector& dist) {\n",
118 | " // min priority_queue of vertices that need to be processed\n",
119 | " // stores pair of \n",
120 | " priority_queue, greater > pq;\n",
121 | " dist.resize(G.nodeCount());\n",
122 | " fill(dist.begin(), dist.end(), INT_MAX); // initialize distance vecrot to some large int\n",
123 | " vector visited(G.nodeCount(), false);\n",
124 | " dist[source] = 0; // distance of source from source is 0\n",
125 | " pq.push({0, source}); // source node's {weight, vertex}\n",
126 | " while (! pq.empty()) {\n",
127 | " int u = pq.top().second;\n",
128 | " pq.pop();\n",
129 | " // Single Destination:\n",
130 | " // if interested to find the path to one destination\n",
131 | " // check here if u == dest node; break if so\n",
132 | " if (visited[u]) continue; // if u already visited get next smaller weight u\n",
133 | " visited[u] = true; // mark u as visited\n",
134 | " for(auto p: G.neighbors(u)) { // explore all the neighbors of u\n",
135 | " int v = p.first; // let's check a neighbor v of u\n",
136 | " if (visited[v]) continue; // if v is already visited; move to next neighbor\n",
137 | " int w = p.second; //otherwise: w = w(u, v)\n",
138 | " // is this the shorter path to v via u?\n",
139 | " int d = dist[u] + w; // newd = dist(source, u) + w(u, v)\n",
140 | " if (d < dist[v]) { // newd < dist(source, v)\n",
141 | " dist[v] = d; // update the dist(source, v)\n",
142 | " pq.push({d, v}); // add {d, v} pair to the priority queue\n",
143 | " // update parent vector if path needs to be recorded\n",
144 | " //parent[v] = u; // use this edge: u->v \n",
145 | " }\n",
146 | " }\n",
147 | " }\n",
148 | "}"
149 | ]
150 | },
151 | {
152 | "cell_type": "markdown",
153 | "metadata": {},
154 | "source": [
155 | "## apply and test Dijkstra's SSSP\n",
156 | "- let's create Graph ADT using adjacency list\n",
157 | "- use it to represent some graph\n",
158 | "- test Diajkstra's SSSP algorithm using the graph"
159 | ]
160 | },
161 | {
162 | "cell_type": "code",
163 | "execution_count": null,
164 | "metadata": {},
165 | "outputs": [],
166 | "source": [
167 | "// Directed Graph using Adjacency List\n",
168 | "// updae addEdge() for Undirected Graph\n",
169 | "class Graph {\n",
170 | " private:\n",
171 | " vector > graph; // list stores pair of neighbor id and weight\n",
172 | " \n",
173 | " public:\n",
174 | " Graph(size_t n) {\n",
175 | " for (int i=0; i v; // create an empty list of int, int pair type\n",
177 | " graph.push_back(v);\n",
178 | " }\n",
179 | " }\n",
180 | " \n",
181 | " // return the number of vertices/nodes\n",
182 | " size_t nodeCount() {\n",
183 | " return graph.size();\n",
184 | " }\n",
185 | " \n",
186 | " // add a new edge from node u to node v, with weight w\n",
187 | " // assumes nodes are numbered from 0 to n-1\n",
188 | " void addEdge(int u, int v, int w) {\n",
189 | " graph[u].push_back({v, w});\n",
190 | " // if undirected graph must add edge from v to u\n",
191 | " // graph[v].push_bck({u, w}); \n",
192 | " }\n",
193 | "\n",
194 | " // returns list of pairs containing neighbors of u, and weight\n",
195 | " list neighbors(int u) {\n",
196 | " return graph[u];\n",
197 | " }\n",
198 | "};"
199 | ]
200 | },
201 | {
202 | "cell_type": "markdown",
203 | "metadata": {},
204 | "source": [
205 | "
"
206 | ]
207 | },
208 | {
209 | "cell_type": "code",
210 | "execution_count": null,
211 | "metadata": {},
212 | "outputs": [],
213 | "source": [
214 | "// let's represent above directed graph\n",
215 | "// A->0, B->1, C->2, D->3, E->4\n",
216 | "Graph graph(5);\n",
217 | "vector dist;"
218 | ]
219 | },
220 | {
221 | "cell_type": "code",
222 | "execution_count": null,
223 | "metadata": {},
224 | "outputs": [],
225 | "source": [
226 | "graph.addEdge(0, 1, 10);\n",
227 | "graph.addEdge(0, 3, 20);\n",
228 | "graph.addEdge(0, 2, 3);\n",
229 | "graph.addEdge(1, 3, 5);\n",
230 | "graph.addEdge(2, 1, 2);\n",
231 | "graph.addEdge(2, 4, 15);\n",
232 | "graph.addEdge(3, 4, 11);"
233 | ]
234 | },
235 | {
236 | "cell_type": "code",
237 | "execution_count": null,
238 | "metadata": {},
239 | "outputs": [],
240 | "source": [
241 | "int source = 0;"
242 | ]
243 | },
244 | {
245 | "cell_type": "code",
246 | "execution_count": null,
247 | "metadata": {},
248 | "outputs": [],
249 | "source": [
250 | "Dijkstra(graph, source, dist);"
251 | ]
252 | },
253 | {
254 | "cell_type": "code",
255 | "execution_count": 8,
256 | "metadata": {},
257 | "outputs": [
258 | {
259 | "name": "stdout",
260 | "output_type": "stream",
261 | "text": [
262 | "shortest distances from source A to all the nodes are:\n",
263 | "A ~~> A = 0\n",
264 | "A ~~> B = 5\n",
265 | "A ~~> C = 3\n",
266 | "A ~~> D = 10\n",
267 | "A ~~> E = 18\n"
268 | ]
269 | }
270 | ],
271 | "source": [
272 | "cout << \"shortest distances from source \" << char(source+65) << \" to all the nodes are:\\n\";\n",
273 | "for (int i=0; i< dist.size(); i++)\n",
274 | " cout << char(source+65) << \" ~~> \" << char(i+65) << \" = \" << dist[i] << \"\\n\";"
275 | ]
276 | },
277 | {
278 | "cell_type": "code",
279 | "execution_count": 9,
280 | "metadata": {},
281 | "outputs": [
282 | {
283 | "data": {
284 | "text/plain": [
285 | "2"
286 | ]
287 | },
288 | "execution_count": 9,
289 | "metadata": {},
290 | "output_type": "execute_result"
291 | }
292 | ],
293 | "source": [
294 | "dist.clear();\n",
295 | "source = 2; // C"
296 | ]
297 | },
298 | {
299 | "cell_type": "code",
300 | "execution_count": 10,
301 | "metadata": {},
302 | "outputs": [],
303 | "source": [
304 | "Dijkstra(graph, source, dist);"
305 | ]
306 | },
307 | {
308 | "cell_type": "code",
309 | "execution_count": 11,
310 | "metadata": {},
311 | "outputs": [
312 | {
313 | "name": "stdout",
314 | "output_type": "stream",
315 | "text": [
316 | "shortest distances from source C to all the nodes are:\n",
317 | "C ~~> A = Impossible\n",
318 | "C ~~> B = 2\n",
319 | "C ~~> C = 0\n",
320 | "C ~~> D = 7\n",
321 | "C ~~> E = 15\n"
322 | ]
323 | }
324 | ],
325 | "source": [
326 | "cout << \"shortest distances from source \" << char(source+65) << \" to all the nodes are:\\n\";\n",
327 | "for (int i=0; i< dist.size(); i++)\n",
328 | " if (dist[i] == INT_MAX)\n",
329 | " cout << char(source+65) << \" ~~> \" << char(i+65) << \" = \" << \"Impossible\" << \"\\n\";\n",
330 | " else\n",
331 | " cout << char(source+65) << \" ~~> \" << char(i+65) << \" = \" << dist[i] << \"\\n\";"
332 | ]
333 | },
334 | {
335 | "cell_type": "markdown",
336 | "metadata": {},
337 | "source": [
338 | "### How can you tell if there's a path from source to a destination?\n",
339 | "- if the distance(source, destination) is NOT the max sentinel value after running Dijkstra's SSSP"
340 | ]
341 | },
342 | {
343 | "cell_type": "markdown",
344 | "metadata": {},
345 | "source": [
346 | "## Time Complexity of Dijkstra's algorithm\n",
347 | "- bulk of the cost comes from the loop which depends on the running time of priority queue\n",
348 | "- because nodes are added into the priority queue repeatedly with different weight while exploring |E| edges, it'll raise the number of elements in the min-heap from $O(|V|)$ to $O(|E|)$\n",
349 | "- when the graph is sparse, its cost is $O(|V|+|E|)log(|E|)$ in the worst case\n",
350 | "- when the graph is dense, $|E|$ approaces $|V|^2$, so the cost can be as much as $O(|V|^2log|E|)$ in the worst case"
351 | ]
352 | },
353 | {
354 | "cell_type": "markdown",
355 | "metadata": {},
356 | "source": [
357 | "## Exercises\n",
358 | "1. Practice how Dijkstra's algorithm works using simulation at the end of: https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/GraphShortest.html\n",
359 | "- George - https://open.kattis.com/problems/george\n",
360 | " - SSSP with extra weight time for some edge\n",
361 | " - SSSP to a single destination\n",
362 | "- Single source shortest path, non-negative weights: https://open.kattis.com/problems/shortestpath1\n",
363 | "- Flowery Trail - https://open.kattis.com/problems/flowerytrail\n",
364 | " - multiple paths with same minimum weight\n",
365 | " - traceback paths\n",
366 | "- Honey Heist - https://open.kattis.com/problems/honeyheist\n",
367 | "- Geezer Scripts - https://open.kattis.com/problems/geezerscripts\n",
368 | " - user max priority queue on remaining health from 1 to N\n",
369 | " - in order to continue to fight to determine winnner, use division to detect winner\n",
370 | " - whoever lasts longer rounds will win; remember player attacks first!\n",
371 | "- Horror List - https://open.kattis.com/problems/horror\n",
372 | " - use HI as dist; run SSSP from horror list\n",
373 | " - report the index of max HI/dist value after running SSSP from all the horror list\n",
374 | "- Tweak Dijkstra's algorithm to record path so that you can print shortest path from source to all other nodes\n",
375 | "- Apply Dijkstra's algorithm to adjacency matrix-based graph\n",
376 | "- Tweak Dijkstra's algoirithm to find shortest path to a single destination and test it"
377 | ]
378 | },
379 | {
380 | "cell_type": "code",
381 | "execution_count": null,
382 | "metadata": {},
383 | "outputs": [],
384 | "source": []
385 | }
386 | ],
387 | "metadata": {
388 | "kernelspec": {
389 | "display_name": "C++14",
390 | "language": "C++14",
391 | "name": "xcpp14"
392 | },
393 | "language_info": {
394 | "codemirror_mode": "text/x-c++src",
395 | "file_extension": ".cpp",
396 | "mimetype": "text/x-c++src",
397 | "name": "c++",
398 | "version": "14"
399 | }
400 | },
401 | "nbformat": 4,
402 | "nbformat_minor": 2
403 | }
404 |
--------------------------------------------------------------------------------
/Hashing.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Hashing\n",
8 | "- https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/HashIntro.html\n",
9 | "\n",
10 | "## Introduction\n",
11 | "- method for storing and retrieving records from a database\n",
12 | "- lets you search/insert/delete records based on key\n",
13 | "- when properly implemented, these operations can be done in $O(1)$\n",
14 | " - as opposed to $O(log n)$ taken by binary search or BST\n",
15 | "- hashing principle is simple but proper implementation is difficult"
16 | ]
17 | },
18 | {
19 | "cell_type": "markdown",
20 | "metadata": {},
21 | "source": [
22 | "## Terminologies\n",
23 | "### Hash Table\n",
24 | "- records are stored in an array called **hash table**, let's say **HT**\n",
25 | "\n",
26 | "### Hash Function\n",
27 | "- finds the position of search key $K$ in $HT$ containting the record associated with $K$\n",
28 | "- the goal is to arrange things such that, for any $K$ and hash function $hash$, $i = hash(K)$\n",
29 | "- locations are usually numbered from $0$ to **N-1**\n",
30 | "- See: https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/HashIntro.html for a simple demo"
31 | ]
32 | },
33 | {
34 | "cell_type": "markdown",
35 | "metadata": {},
36 | "source": [
37 | "## Pros and Cons of Hashing\n",
38 | "- not good for applications with duplicate keys or multiple records with same key\n",
39 | "- not good for answering range queries; e.g., retrieve all records where key >= value and <= another_value\n",
40 | "\n",
41 | "- great choice for exact key matching\n",
42 | "- suitable for both in-memory and disk-based searching (most databases use this technique besides B-tree)"
43 | ]
44 | },
45 | {
46 | "cell_type": "markdown",
47 | "metadata": {},
48 | "source": [
49 | "## Hash Function Principles\n",
50 | "- when large range of values are hashed and stored into small number of slots, collision will likely occur\n",
51 | "- collisions occurs when two records hash to the same slot/index in the table\n",
52 | "- E.g. Birthday Paradox: if there are 23 students in a class, there's 50% probability that two will share a birthday\n",
53 | " - even though there are 365 days; 100% when there are 367\n",
54 | "- **HT** collusion depends on the distribution of the keys which we typically do not have control over\n",
55 | "- generally, pick a hash function that maps keys to slots in a way that makes each slot in the hash table have equal probability of being filled for the actual set of keys being used"
56 | ]
57 | },
58 | {
59 | "cell_type": "markdown",
60 | "metadata": {},
61 | "source": [
62 | "## Sample Hash Functions\n",
63 | "\n",
64 | "### 1. Simple Mod Function\n",
65 | "- hash function to store integers in a table with 10 slots"
66 | ]
67 | },
68 | {
69 | "cell_type": "code",
70 | "execution_count": 2,
71 | "metadata": {},
72 | "outputs": [],
73 | "source": [
74 | "#include \n",
75 | "#include \n",
76 | "#include \n",
77 | "#include //sleep thread\n",
78 | "#include \n",
79 | "#include \n",
80 | "\n",
81 | "using namespace std;"
82 | ]
83 | },
84 | {
85 | "cell_type": "code",
86 | "execution_count": 3,
87 | "metadata": {},
88 | "outputs": [],
89 | "source": [
90 | "// 10 slots: 0-9\n",
91 | "int intHash(int num) {\n",
92 | " return num%10;\n",
93 | "}"
94 | ]
95 | },
96 | {
97 | "cell_type": "code",
98 | "execution_count": 4,
99 | "metadata": {},
100 | "outputs": [],
101 | "source": [
102 | "int nums[10] = {};"
103 | ]
104 | },
105 | {
106 | "cell_type": "code",
107 | "execution_count": 5,
108 | "metadata": {},
109 | "outputs": [],
110 | "source": [
111 | "int getRandomNumber() {\n",
112 | " srand(time(NULL)); // use current time to generate random number\n",
113 | " return rand()%100;\n",
114 | "}"
115 | ]
116 | },
117 | {
118 | "cell_type": "code",
119 | "execution_count": 8,
120 | "metadata": {},
121 | "outputs": [],
122 | "source": [
123 | "// get 10 random numbers and insert into nums table\n",
124 | "for (int i=0; i<10; i++) {\n",
125 | " int num = getRandomNumber();\n",
126 | " // wait for a second so; we get new random number\n",
127 | " //std::this_thread::sleep_for(std::chrono::milliseconds(1000));\n",
128 | " usleep(1000); // sleep for microseconds\n",
129 | " int index = intHash(num);\n",
130 | " nums[index] = num;\n",
131 | "}"
132 | ]
133 | },
134 | {
135 | "cell_type": "code",
136 | "execution_count": 9,
137 | "metadata": {},
138 | "outputs": [
139 | {
140 | "name": "stdout",
141 | "output_type": "stream",
142 | "text": [
143 | "30 81 2 23 74 95 16 37 88 79 "
144 | ]
145 | }
146 | ],
147 | "source": [
148 | "// see all the numbers stored\n",
149 | "for (int i=0; i<10; i++) {\n",
150 | " cout << nums[i] << \" \";\n",
151 | "}"
152 | ]
153 | },
154 | {
155 | "cell_type": "markdown",
156 | "metadata": {},
157 | "source": [
158 | "### 2. Binning\n",
159 | "- if keys are in the given range say 0 to 999, and we've a hash table of size 10\n",
160 | "- simply divide the key value by 100\n",
161 | "- so all keys in the range 0-99 -> 0, 100-199 -> 1, and so on\n",
162 | " - record with $K$ is stored at index $K$/$X$ from some value $X$ (using integer division)\n",
163 | "- this technqiue is called binning"
164 | ]
165 | },
166 | {
167 | "cell_type": "markdown",
168 | "metadata": {},
169 | "source": [
170 | "### 3. Mid-Square Method\n",
171 | "- good hash function for integer key values\n",
172 | "- method:\n",
173 | " 1. square the key value\n",
174 | " - take out the middle $r$ bits of the result \n",
175 | " - gives the value in the range 0 to $2^r - 1$\n",
176 | "- e.g.: say records are 4-digit numbers in base 10\n",
177 | " - the goal is to hash these key values to a table of size 100 (range of 0-99)\n",
178 | " - equivalent to 2 digits in base 10; so $r = 2$\n",
179 | " - say $K$ = 4567\n",
180 | " - $K^2$ = 208**57**489 - the highlighted middle two digits is the index\n",
181 | " - middle digits are affected by everydigit of the original key value"
182 | ]
183 | },
184 | {
185 | "cell_type": "markdown",
186 | "metadata": {},
187 | "source": [
188 | "## Simple Hash Function for Strings\n",
189 | "- sum of ASCII value of all the characters in the string"
190 | ]
191 | },
192 | {
193 | "cell_type": "code",
194 | "execution_count": null,
195 | "metadata": {},
196 | "outputs": [],
197 | "source": [
198 | "#include \n",
199 | "#include \n",
200 | "#include \n",
201 | "using namespace std;"
202 | ]
203 | },
204 | {
205 | "cell_type": "code",
206 | "execution_count": null,
207 | "metadata": {},
208 | "outputs": [],
209 | "source": [
210 | "// hash str to table of size M\n",
211 | "int strHash(string str, int M) {\n",
212 | " int sum = 0;\n",
213 | " for (char c: str)\n",
214 | " sum += int(c);\n",
215 | " return sum%M;\n",
216 | "}"
217 | ]
218 | },
219 | {
220 | "cell_type": "code",
221 | "execution_count": null,
222 | "metadata": {},
223 | "outputs": [],
224 | "source": [
225 | "cout << strHash(\"Hello World!\", 5);"
226 | ]
227 | },
228 | {
229 | "cell_type": "code",
230 | "execution_count": null,
231 | "metadata": {},
232 | "outputs": [],
233 | "source": [
234 | "cout << strHash(\"John Legend\", 5);"
235 | ]
236 | },
237 | {
238 | "cell_type": "markdown",
239 | "metadata": {},
240 | "source": [
241 | "### String Folding\n",
242 | "- process string N bytes/chars at a time\n",
243 | "- integer values for the N-byte chunks are added together\n",
244 | "- convert the resulting sum to 0-M using modulus operator"
245 | ]
246 | },
247 | {
248 | "cell_type": "code",
249 | "execution_count": null,
250 | "metadata": {},
251 | "outputs": [],
252 | "source": [
253 | "// use folding on a string, summed 4 bytes at a time\n",
254 | "int strHashFold(string str, int M) {\n",
255 | " long long unsigned int sum = 0;\n",
256 | " int mul = 1;\n",
257 | " for (int i=0; i\n",
312 | "- records within the slot's list can be ordered in several ways:\n",
313 | " - insertion order; key value order; frequency of access, etc.\n",
314 | " - ordering provides an advantage in the case of an unsuccessful search (stop early)\n",
315 | "- open hashing is most appropriate when the hash table is kept in main memory"
316 | ]
317 | },
318 | {
319 | "cell_type": "markdown",
320 | "metadata": {},
321 | "source": [
322 | "## Closed Hashing\n",
323 | "- bucket hashing is used to store all records directly in the hash table\n",
324 | "- each record, $R$ has a **home position**; i.e., **h($K$)**\n",
325 | "- if another record alread occupies where $R$ needs to be inserted, use collision resolution policy to determine another available slot in the table\n",
326 | "\n",
327 | "### Bucket Hashing\n",
328 | "- group hash table into **buckets**\n",
329 | "- $M$ slots of hash table are divided into $B$ buckets; each bucket with $M/B$ slots\n",
330 | "- hash function assigns each record to the first slot within the one of the buckets\n",
331 | " - if this slot is already occupied, bucket slots are searched sequentially until an open slot is found\n",
332 | " - if a bucket is entirely full, the record is stored in **overflow bucket** of infinite capacity at the end of the table\n",
333 | " - all buckts share the same overflow bucket\n",
334 | " - a good implementation will use a hash function that distributes the records evenly among the buckets so that as few records as possible go into the overflow bucket\n",
335 | "- Visualize bucket hashing demo here: https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/BucketHash.html#id1\n",
336 | "\n",
337 | "### Alternate Approach\n",
338 | "- pretend there are no buckets; so use $N$ whole slots as home position\n",
339 | "- if the home position is full, then search through the rest of the bucket to find an empty slot\n",
340 | "- his reduces initial collisions as each slot can be a home position rather than just the first slot in the bucket\n",
341 | "- visualize alternate closed hashing technique here: https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/BucketHash.html#an-alternate-approach"
342 | ]
343 | },
344 | {
345 | "cell_type": "code",
346 | "execution_count": null,
347 | "metadata": {},
348 | "outputs": [],
349 | "source": []
350 | }
351 | ],
352 | "metadata": {
353 | "kernelspec": {
354 | "display_name": "C++14",
355 | "language": "C++14",
356 | "name": "xcpp14"
357 | },
358 | "language_info": {
359 | "codemirror_mode": "text/x-c++src",
360 | "file_extension": ".cpp",
361 | "mimetype": "text/x-c++src",
362 | "name": "c++",
363 | "version": "-std=c++14"
364 | }
365 | },
366 | "nbformat": 4,
367 | "nbformat_minor": 4
368 | }
369 |
--------------------------------------------------------------------------------
/Heaps-PriorityQueues.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Priority Queues and Heap\n",
8 | "- https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/Heaps.html\n",
9 | "\n",
10 | "## Table of Contents\n",
11 | "- **[Heaps & Priority Queues](#intro)**
\n",
12 | "- **[Push Heap](#push)**
\n",
13 | "- **[Make Heap](#make)**
\n",
14 | "- **[Pop Heap](#pop)**
\n",
15 | "- **[Max Heap Implementation](#maxheap)**
"
16 | ]
17 | },
18 | {
19 | "cell_type": "markdown",
20 | "metadata": {},
21 | "source": [
22 | ""
23 | ]
24 | },
25 | {
26 | "cell_type": "markdown",
27 | "metadata": {},
28 | "source": [
29 | "## Priority Queues\n",
30 | "- in real-life and in computing applications, we may have to choose the next \"most important\" from a collection of people, tasks, or objects\n",
31 | " - doctors in a hospital emergency room often choose to see next \"most critical\" patient\n",
32 | " - operating systems picks programs (jobs) with the highest priority\n",
33 | "- when collection of objects is organized by importance or priority, we call this a **priority queue**\n",
34 | " - normal queue is not efficient as it takes $\\Theta(n)$ time to search for the next highest priority element\n",
35 | "\n",
36 | "## Priority Queue Applications\n",
37 | "- can be applied to solving graph problems such as single-source shortest paths (SSSP) and minimal-cost spanning tree (MST)\n",
38 | "\n",
39 | "## Representing Priority Queue\n",
40 | "- how should we effectively represent priority queue?\n",
41 | "- a list whether sorted or not, will require $\\Theta(n)$ time for either insertion or removal\n",
42 | "- BST would require $\\Theta(nlogn)$ time in the average case; however BST can become unbalanced leading to bad performance $O(n^2)$\n",
43 | "- Heap data structrue is an efficient way!\n",
44 | "\n",
45 | "## Heap\n",
46 | "- **heap** data structure is used to represent priority queues\n",
47 | "- heap is also the name for a memory segment (**free store**)\n",
48 | "- two properties:\n",
49 | " 1. it is a complete binary tree\n",
50 | " - heaps are nearly always implemented using the array representation\n",
51 | " 2. the values stored in a heap data structure are partially ordered\n",
52 | " - there's a relationship between the value stored at any node and the values of its children\n",
53 | " - no relationship between the siblings (unlike BST)\n",
54 | "- two types of heap:\n",
55 | " 1. max heap\n",
56 | " - every node stores a value that is **greater** than or equal to the value of either of its children\n",
57 | " - by its definition, root stores the maximum of all values in the tree\n",
58 | " 2. min heap\n",
59 | " - every node stores a value that is **less** than or equal to that of its children\n",
60 | " - by its definition, root stores the minimum of all values in the tree\n",
61 | "- Heapsort uses max heap\n",
62 | "- Replacement Selection algorithm used for external sorting uses min heap"
63 | ]
64 | },
65 | {
66 | "cell_type": "markdown",
67 | "metadata": {},
68 | "source": [
69 | "## Building Heap\n",
70 | "- Two ways:\n",
71 | " 1. push heap one element at a time\n",
72 | " 2. make heap from given list of elements"
73 | ]
74 | },
75 | {
76 | "cell_type": "markdown",
77 | "metadata": {},
78 | "source": [
79 | ""
80 | ]
81 | },
82 | {
83 | "cell_type": "markdown",
84 | "metadata": {},
85 | "source": [
86 | "## Push Heap\n",
87 | "- similar to: https://en.cppreference.com/w/cpp/algorithm/push_heap \n",
88 | "- useful when all elements are not available at once\n",
89 | "- algorithm steps:\n",
90 | " 1. first copy the data, $V$ at the last index\n",
91 | " - move $V$ to the right place by comparing to its parent's value\n",
92 | " 1. if the value of $V$ is less than or equal to the value of its parent, it is in the correct position\n",
93 | " - if the value of $V$ is greater than that of its parent, the two elements swap positions\n",
94 | " - repeat 2 until $V$ reaches its correct position\n",
95 | "- visualize heap push/insert: https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/Heaps.html\n",
96 | "- running time complexity:\n",
97 | " - since the height of a complete binary tree with $n$ nodes is $(logn)$, each call to push takes $O(logn)$ time in the worst case, (move from the bottom to the top)\n",
98 | " - so, takes $O(nlogn)$ time in the worst case\n",
99 | " \n",
100 | "### push heap operation\n",
101 | "- let's say we have values from 1..7 we want to push to a max heap one element at a time.\n",
102 | "- final heap looks like this:
\n",
103 | "- Heap in above figure is built by pushing one element at a time with a total of (11 swaps):\n",
104 | " - (2, 1), (3, 2), (4, 1), (4, 2), (4, 3), (5, 3), (5, 4), (6, 2), (6, 5), (7, 5), (7, 6)\n",
105 | "- visualize it here pushing one element at a time: https://visualgo.net/en/heap"
106 | ]
107 | },
108 | {
109 | "cell_type": "markdown",
110 | "metadata": {},
111 | "source": [
112 | ""
113 | ]
114 | },
115 | {
116 | "cell_type": "markdown",
117 | "metadata": {},
118 | "source": [
119 | "## Make Heap\n",
120 | "- similar to: https://en.cppreference.com/w/cpp/algorithm/make_heap\n",
121 | "- useful when all $n$ values are available at the beginning of the building process\n",
122 | "- make heap is faster than push heap one element at a time\n",
123 | "\n",
124 | "### make heap operation\n",
125 | "- let's say we have values 1..7 already stored in some sequence data structure like vector as shown in the following figure: \n",
126 | "
\n",
127 | "- start pushing down from 2nd last level and up\n",
128 | "- with the total of 4 swaps (3, 7), (2, 5), (1, 7), (1, 6)\n",
129 | " - the final max heap looks like the following:\n",
130 | "
\n",
131 | "- visualize make heap operation: https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/Heaps.html#building-a-heap\n",
132 | "\n",
133 | "### algorithm steps (based on induction/recursion)\n",
134 | "1. suppose that left and right subtrees of the root are already heaps, and $R$ is the name of the element at the root
\n",
135 | "2. two possibilities:\n",
136 | " 1. $R$ has value greater than or equal to both children (done!)\n",
137 | " 3. $R$ has a value less than one or both of its children\n",
138 | " - **\"push down\"** $R$ until it's greater than its children, or is a leaf node\n",
139 | " - keep exchanging $R$ with the child that has greater value resulting heap\n",
140 | " \n",
141 | "\n",
142 | "### Running time complexity\n",
143 | "- make heap takes $O(n)$ in the worst case better than $O(nlogn)$ (building heap one element at a time)\n",
144 | "- Compared to BST:\n",
145 | " - better than $O(n^2)$ worst-case and $O(nlogn)$ average-case time required to build BST"
146 | ]
147 | },
148 | {
149 | "cell_type": "markdown",
150 | "metadata": {},
151 | "source": [
152 | ""
153 | ]
154 | },
155 | {
156 | "cell_type": "markdown",
157 | "metadata": {},
158 | "source": [
159 | "## Pop Heap \n",
160 | "- remove and return the maximum value from the max heap\n",
161 | "- similar to: https://en.cppreference.com/w/cpp/algorithm/pop_heap\n",
162 | "- algorithm steps:\n",
163 | " 1. swap the first and the last positions\n",
164 | " 2. decrement the heap size by one\n",
165 | " 3. since it's no longer a max heap, push the top element down as appropriate\n",
166 | " 4. return the max element\n",
167 | "- visualize it here: Removing from the heap section- https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/Heaps.html\n",
168 | "- because the heap is $logn$ levels deep, the cost of deleting the maximum element is $\\Theta(logn)$ in the average and worst cases"
169 | ]
170 | },
171 | {
172 | "cell_type": "markdown",
173 | "metadata": {},
174 | "source": [
175 | ""
176 | ]
177 | },
178 | {
179 | "cell_type": "markdown",
180 | "metadata": {},
181 | "source": [
182 | "## Max Heap Implementation\n",
183 | "- implemented using array-based complete binary tree\n",
184 | "- https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/Heaps.html\n"
185 | ]
186 | },
187 | {
188 | "cell_type": "code",
189 | "execution_count": 1,
190 | "metadata": {},
191 | "outputs": [],
192 | "source": [
193 | "#include \n",
194 | "#include \n",
195 | "#include \n",
196 | "#include \n",
197 | "#include \n",
198 | "#include \n",
199 | "\n",
200 | "using namespace std;"
201 | ]
202 | },
203 | {
204 | "cell_type": "code",
205 | "execution_count": 2,
206 | "metadata": {
207 | "code_folding": []
208 | },
209 | "outputs": [],
210 | "source": [
211 | "// Max-heap ADT\n",
212 | "// Max Priority-Queue\n",
213 | "template\n",
214 | "class MaxHeap {\n",
215 | " private:\n",
216 | " vector heap;\n",
217 | " size_t max_size;\n",
218 | " size_t size;\n",
219 | " \n",
220 | " //return true if given pos is a leaf position, false otherwise\n",
221 | " bool isLeaf(size_t pos) {\n",
222 | " return (pos >= size/2 && (pos < size));\n",
223 | " }\n",
224 | " \n",
225 | " // return leftChild's index given a parent's index\n",
226 | " int leftChild(size_t parentIndex) {\n",
227 | " if (parentIndex >= size/2) return -1;\n",
228 | " return 2*parentIndex + 1;\n",
229 | " }\n",
230 | " \n",
231 | " // return rigthChild's index given a parent's index\n",
232 | " int rightChild(size_t parentIndex) {\n",
233 | " if (parentIndex >= (size-1)/2) return -1;\n",
234 | " return 2*parentIndex + 2;\n",
235 | " }\n",
236 | " \n",
237 | " // return parent's index given child's index\n",
238 | " int parent(size_t childIndex) {\n",
239 | " if (childIndex <= 0) return -1;\n",
240 | " return (childIndex-1)/2;\n",
241 | " }\n",
242 | " \n",
243 | " // heapify contents of heap\n",
244 | " // https://en.cppreference.com/w/cpp/algorithm/make_heap\n",
245 | " void makeHeap() {\n",
246 | " // start pushing down from 2nd last level and up\n",
247 | " for(int i=size/2 - 1; i>=0; i--) pushDown(i);\n",
248 | " }\n",
249 | " \n",
250 | " // push the element down to its correct place\n",
251 | " void pushDown(size_t pos) {\n",
252 | " if ((pos < 0) || (pos >= size)) return; //illegal position\n",
253 | " // push down until the pos is a leaf or heap is built\n",
254 | " while(!isLeaf(pos)) {\n",
255 | " // find the index of the larger of the two children\n",
256 | " int j = leftChild(pos); // let's say left child is greater\n",
257 | " // check if the right sibling is greater than left\n",
258 | " // first check if j+1 doesn't go outof bounds or right child exists\n",
259 | " if (( j < (size-1)) && (heap[j] < heap[j+1]))\n",
260 | " ++j; // j+1 is index of child with greater value\n",
261 | " // if value at pos is larger than its larger of the two children; its a heap \n",
262 | " if (heap[pos] >= heap[j]) return;\n",
263 | " swap(heap[pos], heap[j]); //\n",
264 | " pos = j; //move down to new pos\n",
265 | " }\n",
266 | " }\n",
267 | " \n",
268 | " public:\n",
269 | " MaxHeap(size_t max_size, vector items) {\n",
270 | " this->max_size = max_size;\n",
271 | " this->heap.resize(max_size);\n",
272 | " this->size = items.size();\n",
273 | " heap = items;\n",
274 | " makeHeap();\n",
275 | " }\n",
276 | " \n",
277 | " //return the current size of the heap\n",
278 | " size_t heapSize() const { return this->size; }\n",
279 | " \n",
280 | " bool isEmpty() const { return this->size == 0; }\n",
281 | " \n",
282 | " bool isFull() const { return this->size == this->max_size; }\n",
283 | " \n",
284 | " // insert a value into heap\n",
285 | " // https://en.cppreference.com/w/cpp/algorithm/push_heap \n",
286 | " // insert value at the end and shift up to its correct location\n",
287 | " void push(const T &value) {\n",
288 | " if (isFull()) { // Heap is full...\n",
289 | " return;\n",
290 | " }\n",
291 | " int curr = size++; // use size as current index and increment it\n",
292 | " heap[curr] = value; // start at the end\n",
293 | " // now shift up until curr's parent's key > curr's key\n",
294 | " while ((curr > 0) && (heap[parent(curr)] < heap[curr])) {\n",
295 | " swap(heap[parent(curr)], heap[curr]);\n",
296 | " curr = parent(curr);\n",
297 | " }\n",
298 | " }\n",
299 | " \n",
300 | " // remove and return the max value from the heap\n",
301 | " // https://en.cppreference.com/w/cpp/algorithm/pop_heap\n",
302 | " T pop() {\n",
303 | " assert(size > 0); // can't pop from empty heap\n",
304 | " swap(heap[0], heap[--size]); //swap maximum with last value\n",
305 | " if (size != 0) // not on last element\n",
306 | " pushDown(0); //put new heap root val in correct place\n",
307 | " return heap[size];\n",
308 | " }\n",
309 | "};"
310 | ]
311 | },
312 | {
313 | "cell_type": "code",
314 | "execution_count": 3,
315 | "metadata": {},
316 | "outputs": [],
317 | "source": [
318 | "// Test Max-heap\n",
319 | "// see building the heap visualization in the above open-dsa link\n",
320 | "vector nums = {1, 2, 3, 4, 5, 6, 7};"
321 | ]
322 | },
323 | {
324 | "cell_type": "code",
325 | "execution_count": 4,
326 | "metadata": {},
327 | "outputs": [],
328 | "source": [
329 | "// make heap from nums vector\n",
330 | "MaxHeap heap(100, nums);"
331 | ]
332 | },
333 | {
334 | "cell_type": "code",
335 | "execution_count": 5,
336 | "metadata": {},
337 | "outputs": [
338 | {
339 | "name": "stdout",
340 | "output_type": "stream",
341 | "text": [
342 | "heap size = 7\n",
343 | "max value = 7\n"
344 | ]
345 | }
346 | ],
347 | "source": [
348 | "cout << \"heap size = \" << heap.heapSize() << endl;\n",
349 | "// pop max element\n",
350 | "cout << \"max value = \" << heap.pop() << endl;"
351 | ]
352 | },
353 | {
354 | "cell_type": "code",
355 | "execution_count": 6,
356 | "metadata": {},
357 | "outputs": [
358 | {
359 | "name": "stdout",
360 | "output_type": "stream",
361 | "text": [
362 | "heap size = 7\n"
363 | ]
364 | }
365 | ],
366 | "source": [
367 | "// push an element\n",
368 | "heap.push(8);\n",
369 | "cout << \"heap size = \" << heap.heapSize() << endl;"
370 | ]
371 | },
372 | {
373 | "cell_type": "code",
374 | "execution_count": 7,
375 | "metadata": {},
376 | "outputs": [
377 | {
378 | "name": "stdout",
379 | "output_type": "stream",
380 | "text": [
381 | "max value = 8\n"
382 | ]
383 | }
384 | ],
385 | "source": [
386 | "cout << \"max value = \" << heap.pop() << endl;"
387 | ]
388 | },
389 | {
390 | "cell_type": "code",
391 | "execution_count": 8,
392 | "metadata": {},
393 | "outputs": [
394 | {
395 | "name": "stdout",
396 | "output_type": "stream",
397 | "text": [
398 | "6\n",
399 | "5\n",
400 | "4\n",
401 | "3\n",
402 | "2\n",
403 | "1\n"
404 | ]
405 | }
406 | ],
407 | "source": [
408 | "while (!heap.isEmpty()) {\n",
409 | " cout << heap.pop() << endl;\n",
410 | "}"
411 | ]
412 | },
413 | {
414 | "cell_type": "code",
415 | "execution_count": 9,
416 | "metadata": {},
417 | "outputs": [
418 | {
419 | "name": "stdout",
420 | "output_type": "stream",
421 | "text": [
422 | "heap size = 0\n"
423 | ]
424 | }
425 | ],
426 | "source": [
427 | "cout << \"heap size = \" << heap.heapSize() << endl;"
428 | ]
429 | },
430 | {
431 | "cell_type": "markdown",
432 | "metadata": {},
433 | "source": [
434 | "### Storing jobs in PriorityQueue"
435 | ]
436 | },
437 | {
438 | "cell_type": "code",
439 | "execution_count": 10,
440 | "metadata": {},
441 | "outputs": [],
442 | "source": [
443 | "class Job {\n",
444 | " public:\n",
445 | " int ID;\n",
446 | " int priority;\n",
447 | " string name;\n",
448 | " bool operator>=(const Job& other) {\n",
449 | " return this->priority >= other.priority;\n",
450 | " }\n",
451 | " \n",
452 | " bool operator<(const Job& other) {\n",
453 | " return this->priority < other.priority;\n",
454 | " }\n",
455 | " \n",
456 | " void print() {\n",
457 | " cout << \"ID: \" << this->ID << \" Priority: \" << this->priority << \" Name: \" << this->name << endl;\n",
458 | " }\n",
459 | "};"
460 | ]
461 | },
462 | {
463 | "cell_type": "code",
464 | "execution_count": 11,
465 | "metadata": {},
466 | "outputs": [],
467 | "source": [
468 | "vector jobs = {{1, 10, \"Print\"}, {3, 30, \"Write\"}, {2, 20, \"Read\"}};"
469 | ]
470 | },
471 | {
472 | "cell_type": "code",
473 | "execution_count": 12,
474 | "metadata": {},
475 | "outputs": [],
476 | "source": [
477 | "MaxHeap jobsQueue(50, jobs);"
478 | ]
479 | },
480 | {
481 | "cell_type": "code",
482 | "execution_count": 13,
483 | "metadata": {},
484 | "outputs": [
485 | {
486 | "name": "stdout",
487 | "output_type": "stream",
488 | "text": [
489 | "heap size = 3\n"
490 | ]
491 | }
492 | ],
493 | "source": [
494 | "cout << \"heap size = \" << jobsQueue.heapSize() << endl;"
495 | ]
496 | },
497 | {
498 | "cell_type": "code",
499 | "execution_count": 14,
500 | "metadata": {},
501 | "outputs": [],
502 | "source": [
503 | "Job j;"
504 | ]
505 | },
506 | {
507 | "cell_type": "code",
508 | "execution_count": 15,
509 | "metadata": {},
510 | "outputs": [
511 | {
512 | "name": "stdout",
513 | "output_type": "stream",
514 | "text": [
515 | "ID: 3 Priority: 30 Name: Write\n"
516 | ]
517 | }
518 | ],
519 | "source": [
520 | "j = jobsQueue.pop();\n",
521 | "j.print();"
522 | ]
523 | },
524 | {
525 | "cell_type": "code",
526 | "execution_count": 16,
527 | "metadata": {},
528 | "outputs": [],
529 | "source": [
530 | "jobsQueue.push({5, 100, \"Connect\"});"
531 | ]
532 | },
533 | {
534 | "cell_type": "code",
535 | "execution_count": 17,
536 | "metadata": {},
537 | "outputs": [
538 | {
539 | "name": "stdout",
540 | "output_type": "stream",
541 | "text": [
542 | "queue size = 3\n",
543 | "highest priority job = ID: 5 Priority: 100 Name: Connect\n"
544 | ]
545 | }
546 | ],
547 | "source": [
548 | "cout << \"queue size = \" << jobsQueue.heapSize() << endl;\n",
549 | "j = jobsQueue.pop();\n",
550 | "cout << \"highest priority job = \";\n",
551 | "j.print();"
552 | ]
553 | },
554 | {
555 | "cell_type": "markdown",
556 | "metadata": {},
557 | "source": [
558 | "## Using MaxHeap as MinHeap\n",
559 | "- reverse the ordering of cost/weight value that determines priority\n",
560 | "- OR\n",
561 | " - -negate the values of cost/weight that determine priority"
562 | ]
563 | },
564 | {
565 | "cell_type": "code",
566 | "execution_count": 18,
567 | "metadata": {},
568 | "outputs": [],
569 | "source": [
570 | "// Reverse the ordering of values to create Min Priority Queue/Min Heap\n",
571 | "class Task {\n",
572 | " public:\n",
573 | " int ID;\n",
574 | " int cost; // priority set based on cost; lower the cost; higher the priority!\n",
575 | " bool operator>=(const Task& other) {\n",
576 | " return this->cost <= other.cost;\n",
577 | " }\n",
578 | " \n",
579 | " bool operator<(const Task& other) {\n",
580 | " return this->cost > other.cost;\n",
581 | " }\n",
582 | " \n",
583 | " void print() {\n",
584 | " cout << \"ID: \" << this->ID << \" cost: \" << this->cost << endl;\n",
585 | " }\n",
586 | "};"
587 | ]
588 | },
589 | {
590 | "cell_type": "code",
591 | "execution_count": 19,
592 | "metadata": {},
593 | "outputs": [],
594 | "source": [
595 | "vector tasks = {{10, 200}, {1, 10}, {5, 50}};"
596 | ]
597 | },
598 | {
599 | "cell_type": "code",
600 | "execution_count": 20,
601 | "metadata": {},
602 | "outputs": [],
603 | "source": [
604 | "MaxHeap minPq(50, tasks);"
605 | ]
606 | },
607 | {
608 | "cell_type": "code",
609 | "execution_count": 21,
610 | "metadata": {},
611 | "outputs": [
612 | {
613 | "name": "stdout",
614 | "output_type": "stream",
615 | "text": [
616 | "ID: 1 cost: 10\n",
617 | "ID: 5 cost: 50\n",
618 | "ID: 10 cost: 200\n"
619 | ]
620 | }
621 | ],
622 | "source": [
623 | "// process all the tasks based on cost; with smaller cost first\n",
624 | "while (!minPq.isEmpty()) {\n",
625 | " Task t = minPq.pop();\n",
626 | " t.print();\n",
627 | "}"
628 | ]
629 | },
630 | {
631 | "cell_type": "code",
632 | "execution_count": 22,
633 | "metadata": {},
634 | "outputs": [],
635 | "source": [
636 | "// MinHeap: negate the values of weights/costs\n",
637 | "// use the same values as we used in the first example above;\n",
638 | "vector nums1 = {1, 2, 3, 4, 5, 6, 7};"
639 | ]
640 | },
641 | {
642 | "cell_type": "code",
643 | "execution_count": 27,
644 | "metadata": {},
645 | "outputs": [],
646 | "source": [
647 | "// negate each value\n",
648 | "for_each(nums1.begin(), nums1.end(), [](int &n){ n *= -1; });"
649 | ]
650 | },
651 | {
652 | "cell_type": "code",
653 | "execution_count": 28,
654 | "metadata": {},
655 | "outputs": [
656 | {
657 | "name": "stdout",
658 | "output_type": "stream",
659 | "text": [
660 | "-1 -2 -3 -4 -5 -6 -7 "
661 | ]
662 | }
663 | ],
664 | "source": [
665 | "for (auto &n: nums1) { cout << n << \" \"; }"
666 | ]
667 | },
668 | {
669 | "cell_type": "code",
670 | "execution_count": 29,
671 | "metadata": {},
672 | "outputs": [],
673 | "source": [
674 | "// build min-heap\n",
675 | "MaxHeap minPqInts(10, nums1);"
676 | ]
677 | },
678 | {
679 | "cell_type": "code",
680 | "execution_count": 31,
681 | "metadata": {},
682 | "outputs": [
683 | {
684 | "name": "stdout",
685 | "output_type": "stream",
686 | "text": [
687 | "-1\n",
688 | "-2\n",
689 | "-3\n",
690 | "-4\n",
691 | "-5\n",
692 | "-6\n",
693 | "-7\n"
694 | ]
695 | }
696 | ],
697 | "source": [
698 | "// process heap/MinPQ one element at a time\n",
699 | "while(!minPqInts.isEmpty()) {\n",
700 | " cout << minPqInts.pop() << endl;\n",
701 | "}"
702 | ]
703 | },
704 | {
705 | "cell_type": "markdown",
706 | "metadata": {},
707 | "source": [
708 | "## Kahoot.it\n",
709 | "- https://play.kahoot.it/v2/lobby?quizId=a1f75bcb-ccfa-4d8a-b777-bcd71f7de2fc"
710 | ]
711 | },
712 | {
713 | "cell_type": "markdown",
714 | "metadata": {},
715 | "source": [
716 | "## Exercises\n",
717 | "1. Consider a node $R$ of a complete binary tree whose value is stored in position $i$ of an array representation for the tree. If $R$ has a parent, where will the parent's position be in the array?\n",
718 | " 1. $2*i+1$\n",
719 | " 2. $i+1$\n",
720 | " - $\\Bigl\\lfloor\\frac{i-1} {2}\\Bigr\\rfloor$\n",
721 | " - $2*i+2$\n",
722 | "\n",
723 | "- Which of these is true statement about the worst-case time for operations on heaps?\n",
724 | " 1. Neither insertion nor removal are better than linear\n",
725 | " - Insertion is better than linear, but removal is not\n",
726 | " - Removal is better than linear, but insertion is not\n",
727 | " - Both insertion and removal are better than linear\n",
728 | " \n",
729 | "- In a max-heap containing $n$ elements, what is the position of the element with the max value?\n",
730 | " 1. $n+1$\n",
731 | " - $0$\n",
732 | " - Possibly in any leaf nodes\n",
733 | " - $2*n+1$\n",
734 | " - $n$\n",
735 | " - $n-1$\n",
736 | " - $2*n+2$\n",
737 | "\n",
738 | "- In a max-heap containing $n$ elements, what is the position of the element with the least/min value?\n",
739 | " 1. $n+1$\n",
740 | " - $0$\n",
741 | " - Possibly in any leaf node\n",
742 | " - $2*n+1$\n",
743 | " - $n$\n",
744 | " - $n-1$\n",
745 | " - $2*n+2$\n",
746 | " \n",
747 | "- In a min-heap containing $n$ elements, what is the position of the element with the least/min value?\n",
748 | " 1. $n+1$\n",
749 | " - $0$\n",
750 | " - Possibly in any leaf node\n",
751 | " - $2*n+1$\n",
752 | " - $n$\n",
753 | " - $n-1$\n",
754 | " - $2*n+2$\n",
755 | " \n",
756 | "- In a min-heap containing $n$ elements, what is the position of the element with the max value?\n",
757 | " 1. $n+1$\n",
758 | " - $0$\n",
759 | " - Possibly in any leaf node\n",
760 | " - $2*n+1$\n",
761 | " - $n$\n",
762 | " - $n-1$\n",
763 | " - $2*n+2$"
764 | ]
765 | },
766 | {
767 | "cell_type": "code",
768 | "execution_count": null,
769 | "metadata": {},
770 | "outputs": [],
771 | "source": []
772 | }
773 | ],
774 | "metadata": {
775 | "kernelspec": {
776 | "display_name": "C++14",
777 | "language": "C++14",
778 | "name": "xcpp14"
779 | },
780 | "language_info": {
781 | "codemirror_mode": "text/x-c++src",
782 | "file_extension": ".cpp",
783 | "mimetype": "text/x-c++src",
784 | "name": "c++",
785 | "version": "14"
786 | }
787 | },
788 | "nbformat": 4,
789 | "nbformat_minor": 4
790 | }
791 |
--------------------------------------------------------------------------------
/Introduction.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "## Introduction\n",
8 | "https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/IntroDSA.html"
9 | ]
10 | },
11 | {
12 | "cell_type": "markdown",
13 | "metadata": {},
14 | "source": [
15 | "- Some problems to think about...\n",
16 | " 1. What is the fastest route from Los Angeles, CA to New York City, NY? \n",
17 | " - how long does it take to get there?\n",
18 | " 2. What is the most reliable source on the Internet to learn about data structures and algorithms?\n",
19 | " 3. Who was the most influential celebrity/politician of last year?\n",
20 | " 4. What is an average salary of a software engineer?\n",
21 | " 5. What is the cheapest way to travel from Grand Junction, CO, to Kathmandu, Nepal?\n",
22 | " 6. How does Apple's Siri know what appointment you have next when you ask it? "
23 | ]
24 | },
25 | {
26 | "cell_type": "markdown",
27 | "metadata": {
28 | "heading_collapsed": true
29 | },
30 | "source": [
31 | "## Computer Science (CS) fundamentals"
32 | ]
33 | },
34 | {
35 | "cell_type": "markdown",
36 | "metadata": {
37 | "hidden": true
38 | },
39 | "source": [
40 | "- the core of CS is representing data so that it can be efficiently stored and retrieved\n",
41 | " - many computer programs sole functionality is to do just that, but as fast as possible. e.g., search engines like, Google, Bing, etc.\n",
42 | "- some programs may do heavy mathematical computation as fast as possible, e.g., wolframalpha computational intelligence (https://www.wolframalpha.com)\n",
43 | " - find factorial(10000) or 10000!\n",
44 | " \n",
45 | "**the study of data structures and the alogrithms that manipulate them to solve a given problem in feasible time and resource is the heart of compuer science**"
46 | ]
47 | },
48 | {
49 | "cell_type": "markdown",
50 | "metadata": {},
51 | "source": [
52 | "## Goals of Data Structure (DS) and Algorithm courses"
53 | ]
54 | },
55 | {
56 | "cell_type": "markdown",
57 | "metadata": {},
58 | "source": [
59 | "1. present a collection of commonly used data structures and algorithms, programmer's basic \"toolkit\"\n",
60 | " - for many problems these toolkit out-of-the box will provide efficient solutions\n",
61 | " - \"toolkit\" forms the basis/foundations to build more advanced data structures\n",
62 | "2. introduce the idea of trade-offs between the costs and benefits associated with every data structure or algorithm, e.g., trade-offs between memory and time\n",
63 | "3. learn to measure the effectiveness of a data structure or algorithm so you can pick the right ones for the job\n",
64 | " - also allows you to quickly judge the merits of new data structures or algorithms that you or others might invent"
65 | ]
66 | },
67 | {
68 | "cell_type": "markdown",
69 | "metadata": {},
70 | "source": [
71 | "## Solving problems"
72 | ]
73 | },
74 | {
75 | "cell_type": "markdown",
76 | "metadata": {},
77 | "source": [
78 | " - the primary job of computer scientists is to solve problems!\n",
79 | " - there are often too many approaches to solve a problem\n",
80 | " - at the heart of computer program designs are two (sometimes conflicting) goals:\n",
81 | " 1. to design an algorithm that is easy to understand, code, and debug\n",
82 | " 2. to design an algorithm that makes efficient use of the computer's resources\n",
83 | " - \"elegant\" solutions meet both these goals!\n",
84 | " - software engineering focuses on goal 1, though we emphasize it from CS1!\n",
85 | " - CS2 and CS3 usually focuses on goal 2."
86 | ]
87 | },
88 | {
89 | "cell_type": "markdown",
90 | "metadata": {},
91 | "source": [
92 | "## Why faster DS and algorithms when we've faster computers?"
93 | ]
94 | },
95 | {
96 | "cell_type": "markdown",
97 | "metadata": {},
98 | "source": [
99 | "- according to Moore's law https://en.wikipedia.org/wiki/Moore%27s_law, no. of transistors in computer's circuit board doubles every two years.\n",
100 | "- so, if processor speed and memory size continue to improve, won't today's hard problem be solved by tomorrow's hardware?\n",
101 | "- additional computing power enables us to tackle more complex problems, such as sophisticated user interfaces such as in mobile devices, bigger problem sizes (big data), or new problems previously deemed computationally infeasible\n",
102 | "- resources are always limited...\n",
103 | "- efficient solution solves the problem within the required *resource constraints*.\n",
104 | " - may require fewer resources than known alternatives, regardless of whether it meets any particular requirements\n",
105 | "- **cost** of a solution is the amount of resources that the solution consumes\n",
106 | " - measured typically in terms of one key resource such as time implying it meets all other resource constraints \n",
107 | " - e.g., fastest solutions on open.kattis.com problems meeting memory requirements: https://open.kattis.com/problems/cd/statistics"
108 | ]
109 | },
110 | {
111 | "cell_type": "markdown",
112 | "metadata": {},
113 | "source": [
114 | "## Selecting a Data Structure"
115 | ]
116 | },
117 | {
118 | "cell_type": "markdown",
119 | "metadata": {},
120 | "source": [
121 | "1. analyze your problem to determine the **basic operations** e.g., inserting data item into the data structure, deleting, finding a specified data item\n",
122 | "- quantify the resource constraints for each operation\n",
123 | "- select the data structure that best meets these requirements\n",
124 | "\n",
125 | "### Some questions to think about to determine the importance of operations\n",
126 | "1. is the application static or dynamic\n",
127 | " - in static applications, data is loaded at the beginning and new data are not inserted\n",
128 | " - in dynamic applications, new data items are inserted and may be inserted in any locations\n",
129 | "- can data items be deleted? this may make the implementation more complicated\n",
130 | "- how are the data items processed? in some well-defined order, random access?"
131 | ]
132 | },
133 | {
134 | "cell_type": "markdown",
135 | "metadata": {},
136 | "source": [
137 | "## Exercises\n",
138 | "1. Which of these is NOT a definition for efficiency in a computer program?\n",
139 | " - it solves the problem within the required resource constraints\n",
140 | " - it requires fewer resources than known alternatives\n",
141 | " - it runs in linear time"
142 | ]
143 | },
144 | {
145 | "cell_type": "code",
146 | "execution_count": null,
147 | "metadata": {},
148 | "outputs": [],
149 | "source": []
150 | }
151 | ],
152 | "metadata": {
153 | "kernelspec": {
154 | "display_name": "C++14",
155 | "language": "C++14",
156 | "name": "xcpp14"
157 | },
158 | "language_info": {
159 | "codemirror_mode": "text/x-c++src",
160 | "file_extension": ".cpp",
161 | "mimetype": "text/x-c++src",
162 | "name": "c++",
163 | "version": "14"
164 | }
165 | },
166 | "nbformat": 4,
167 | "nbformat_minor": 2
168 | }
169 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Ram Basnet
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 |
--------------------------------------------------------------------------------
/MSTKruskals.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Minimum Spanning Tree - Kruskal's Algorithm\n",
8 | "https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/Kruskal.html\n",
9 | "\n",
10 | "### Table of Contents\n",
11 | "- **[Kruskal's Algorithm](#kruskal)**
\n",
12 | "- **[Implementation](#imp)**
\n",
13 | "- **[Analysis of Kruskal's Algorithm and Vs Prim's](#analysis)**
\n",
14 | "- **[Exercises](#exercises)**
"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | ""
22 | ]
23 | },
24 | {
25 | "cell_type": "markdown",
26 | "metadata": {},
27 | "source": [
28 | "## Kruskal's Algorithm\n",
29 | "- another algorithm for finding Minimum Spanning Tree (MST)\n",
30 | "- also a greedy algorithm\n",
31 | " - makes the optimal choice at each step as it attempts to find the overall optimal way to solve the entire problem\n",
32 | "- use [Parent Pointer Tree](./GeneralTreesUnionFind.ipynb) to find and join disjoint sets\n",
33 | "- algorithm steps:\n",
34 | " 1. partition the set of vertices into $V$ [disjoint sets](./GeneralTreesUnionFind.ipynb)\n",
35 | " - each set contains one vertex\n",
36 | " - process the edges in order of weight (sort, or use min heap priority queue)\n",
37 | " - if an edge connects two vertices in dfferent disjoint sets (FIND):\n",
38 | " - add the edge to the MST\n",
39 | " - combine the sets (UNION)\n",
40 | "\n",
41 | " - if the graph is connected, MST will have $|V|-1$ edges\n",
42 | "\n",
43 | "
\n",
44 | "\n",
45 | "### visualize Kruskal's algorithm here: https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/Kruskal.html"
46 | ]
47 | },
48 | {
49 | "cell_type": "code",
50 | "execution_count": 1,
51 | "metadata": {},
52 | "outputs": [],
53 | "source": [
54 | "#include \n",
55 | "#include \n",
56 | "#include // priority_queue\n",
57 | "#include // sizes of integral types\n",
58 | "#include \n",
59 | "#include \n",
60 | "#include \n",
61 | "\n",
62 | "using namespace std;\n",
63 | "\n",
64 | "using iPair = pair; "
65 | ]
66 | },
67 | {
68 | "cell_type": "code",
69 | "execution_count": 2,
70 | "metadata": {},
71 | "outputs": [],
72 | "source": [
73 | "// general Parent-Pointer Tree implementation for UNION/FIND\n",
74 | "class ParPtrTree {\n",
75 | " private:\n",
76 | " vector parents; // parent pointer vector\n",
77 | " vector weights; // weights for weighted union\n",
78 | " public:\n",
79 | " // constructor\n",
80 | " ParPtrTree(size_t size) {\n",
81 | " parents.resize(size); //create parents vector\n",
82 | " fill(parents.begin(), parents.end(), -1); // each node is its own root to start\n",
83 | " weights.resize(size); \n",
84 | " fill(weights.begin(), weights.end(), 1);// set all base weights to 1\n",
85 | " }\n",
86 | " \n",
87 | " // Return the root of a given node with path compression\n",
88 | " // recursive algorithm that makes all ancestors of the current node\n",
89 | " // point to the root\n",
90 | " int FIND(int node) {\n",
91 | " if (parents[node] == -1) return node;\n",
92 | " parents[node] = FIND(parents[node]);\n",
93 | " return parents[node];\n",
94 | " }\n",
95 | " \n",
96 | " // Merge two subtrees if they are different\n",
97 | " void UNION(int node1, int node2) {\n",
98 | " int root1 = FIND(node1);\n",
99 | " int root2 = FIND(node2);\n",
100 | " // MERGE two trees\n",
101 | " if (root1 != root2) {\n",
102 | " if (weights[root1] < weights[root2]) {\n",
103 | " parents[root1] = root2;\n",
104 | " weights[root2] += weights[root1];\n",
105 | " }\n",
106 | " else {\n",
107 | " parents[root2] = root1;\n",
108 | " weights[root1] += weights[root2];\n",
109 | " }\n",
110 | " } \n",
111 | " }\n",
112 | " \n",
113 | " string toString() {\n",
114 | " string nodes = \"nodes:\\t\";\n",
115 | " string prts = \"parents:\\t\";\n",
116 | " for (int i=0; i < this->parents.size(); i++) {\n",
117 | " prts += to_string(this->parents[i]) + '\\t';\n",
118 | " nodes += \" \\t \" + to_string(i); \n",
119 | " }\n",
120 | " return prts + \"\\n\" + nodes;\n",
121 | " }\n",
122 | "};"
123 | ]
124 | },
125 | {
126 | "cell_type": "code",
127 | "execution_count": 3,
128 | "metadata": {},
129 | "outputs": [],
130 | "source": [
131 | "// a structure to represent a weighted edge in graph \n",
132 | "struct Edge \n",
133 | "{ \n",
134 | " int src, dest, weight; \n",
135 | " // for min priority queue \n",
136 | " bool operator<(const Edge &other) const {\n",
137 | " return this->weight > other.weight;\n",
138 | " }\n",
139 | "};"
140 | ]
141 | },
142 | {
143 | "cell_type": "markdown",
144 | "metadata": {},
145 | "source": [
146 | "## Representing Graph using Vector of Edge"
147 | ]
148 | },
149 | {
150 | "cell_type": "code",
151 | "execution_count": 4,
152 | "metadata": {},
153 | "outputs": [],
154 | "source": [
155 | "// a structure to represent undirected \n",
156 | "// and weighted graph \n",
157 | "struct Graph \n",
158 | "{ \n",
159 | " // V -> Number of vertices, E -> Number of edges \n",
160 | " int V, E; \n",
161 | " // graph is stored in a min heap priority_queue\n",
162 | " // Kruskal algo requires working with edges with smallest to highest weight \n",
163 | " priority_queue > edges;\n",
164 | " // constructor\n",
165 | " Graph(int v, int e) {\n",
166 | " V = v;\n",
167 | " E = e;\n",
168 | " }\n",
169 | " \n",
170 | " void addEdge(int u, int v, int w) {\n",
171 | " edges.push({u, v, w});\n",
172 | " }\n",
173 | "};"
174 | ]
175 | },
176 | {
177 | "cell_type": "markdown",
178 | "metadata": {},
179 | "source": [
180 | ""
181 | ]
182 | },
183 | {
184 | "cell_type": "markdown",
185 | "metadata": {},
186 | "source": [
187 | "### Kruskal's Algorithm Implementation"
188 | ]
189 | },
190 | {
191 | "cell_type": "code",
192 | "execution_count": 5,
193 | "metadata": {},
194 | "outputs": [],
195 | "source": [
196 | "// function to construct MST using Kruskal's algorithm \n",
197 | "// returns the total weight of MST\n",
198 | "// edges forming MST are stored in MST vector\n",
199 | "int KruskalMST(Graph& graph, vector & MST) \n",
200 | "{ \n",
201 | " if (graph.E == 0)\n",
202 | " return 0;\n",
203 | "\n",
204 | " int numMST = graph.V; // initially V disjoint classes \n",
205 | " ParPtrTree unionfind(graph.V);\n",
206 | " int weight = 0;\n",
207 | "\n",
208 | " while (numMST > 1 && !graph.edges.empty())\n",
209 | " { \n",
210 | " // pick the smallest edge\n",
211 | " Edge edge = graph.edges.top();\n",
212 | " graph.edges.pop();\n",
213 | " int x = unionfind.FIND(edge.src); // root of src\n",
214 | " int y = unionfind.FIND(edge.dest); // root of dest\n",
215 | " // if src and dest nodes are in different sets\n",
216 | " if (x != y) \n",
217 | " { \n",
218 | " int u = edge.src;\n",
219 | " int v = edge.dest;\n",
220 | " // add weight\n",
221 | " weight += edge.weight;\n",
222 | " // the ordering is not required, but...\n",
223 | " if (u > v) swap(u, v);\n",
224 | " // add u->v edge to MST\n",
225 | " MST.push_back({u, v});\n",
226 | " // combine equiv classes\n",
227 | " unionfind.UNION(u, v);\n",
228 | " numMST--; // one less MST\n",
229 | " } \n",
230 | " } \n",
231 | " return weight;\n",
232 | "}"
233 | ]
234 | },
235 | {
236 | "cell_type": "markdown",
237 | "metadata": {},
238 | "source": [
239 | "### Test Kruskal's Algorithm"
240 | ]
241 | },
242 | {
243 | "cell_type": "markdown",
244 | "metadata": {},
245 | "source": [
246 | "
"
247 | ]
248 | },
249 | {
250 | "cell_type": "code",
251 | "execution_count": 6,
252 | "metadata": {},
253 | "outputs": [],
254 | "source": [
255 | "// represent undirected graph shown in above diagram\n",
256 | "// A->0, B->1, C->2, D->3, E->4, F->5\n",
257 | "Graph graph(6, 8);\n",
258 | "vector MST;"
259 | ]
260 | },
261 | {
262 | "cell_type": "code",
263 | "execution_count": 7,
264 | "metadata": {},
265 | "outputs": [],
266 | "source": [
267 | "// 8 undirected edges\n",
268 | "graph.addEdge(0, 2, 7);\n",
269 | "graph.addEdge(0, 4, 9);\n",
270 | "graph.addEdge(1, 2, 5);\n",
271 | "graph.addEdge(1, 5, 6);\n",
272 | "graph.addEdge(2, 3, 1);\n",
273 | "graph.addEdge(2, 5, 2);\n",
274 | "graph.addEdge(3, 5, 2);\n",
275 | "graph.addEdge(4, 5, 1);"
276 | ]
277 | },
278 | {
279 | "cell_type": "code",
280 | "execution_count": 8,
281 | "metadata": {},
282 | "outputs": [],
283 | "source": [
284 | "int wt;"
285 | ]
286 | },
287 | {
288 | "cell_type": "code",
289 | "execution_count": 9,
290 | "metadata": {},
291 | "outputs": [],
292 | "source": [
293 | "wt = KruskalMST(graph, MST);"
294 | ]
295 | },
296 | {
297 | "cell_type": "code",
298 | "execution_count": 10,
299 | "metadata": {},
300 | "outputs": [
301 | {
302 | "name": "stdout",
303 | "output_type": "stream",
304 | "text": [
305 | "total cost of MST = 16\n",
306 | "MST edges:\n",
307 | "C-D\n",
308 | "E-F\n",
309 | "C-F\n",
310 | "B-C\n",
311 | "A-C\n"
312 | ]
313 | }
314 | ],
315 | "source": [
316 | "cout << \"total cost of MST = \" << wt << endl;\n",
317 | "cout << \"MST edges:\\n\";\n",
318 | "for(auto &p:MST)\n",
319 | " cout << char(p.first+65) << \"-\" << char(p.second+65) << '\\n';\n"
320 | ]
321 | },
322 | {
323 | "cell_type": "markdown",
324 | "metadata": {},
325 | "source": [
326 | ""
327 | ]
328 | },
329 | {
330 | "cell_type": "markdown",
331 | "metadata": {},
332 | "source": [
333 | "## Analysis of Kruskal's Algorithm\n",
334 | "- dominated by the time required to process the edges\n",
335 | "- if path compression and weighted union is used, union/find takes nearly constant time\n",
336 | "- total cost $\\Theta(|E|log|E|)$ in the worst case when nearly all edges must be processed\n",
337 | "- most often need to process only about $|V|$ edges\n",
338 | " - so, cost is ~ $\\Theta(|V| log|E|)$ in the average case\n",
339 | " \n",
340 | "## Comparison with Prim's Algorithm\n",
341 | "- if heap (priority queue) is used and the graph is sparse, cost is $\\Theta((|V| + |E|) log |E|)$\n",
342 | "- if graph is dense, cost can be $\\Theta(|V|^2 + log |E|) = \\Theta(|V|^2 log |V|)$"
343 | ]
344 | },
345 | {
346 | "cell_type": "markdown",
347 | "metadata": {},
348 | "source": [
349 | ""
350 | ]
351 | },
352 | {
353 | "cell_type": "markdown",
354 | "metadata": {},
355 | "source": [
356 | "## Exercises\n",
357 | "1. Minimum Spanning Tree problem: https://open.kattis.com/problems/minspantree\n",
358 | "- A Feast For Cats - https://open.kattis.com/problems/cats\n",
359 | " - Hint: Use Kruskal's\n",
360 | " - if M >= C + TotalMST Weight -> yes!\n",
361 | "- Island Hopping - https://open.kattis.com/problems/islandhopping\n",
362 | " - Hint: distance between two points is the weight (float)\n",
363 | "- Lost Map - https://open.kattis.com/problems/lostmap\n",
364 | " - much faster compared to Prim's\n",
365 | "- Driving Range - https://open.kattis.com/problems/drivingrange\n",
366 | " - Hint: last edge that formed MST"
367 | ]
368 | },
369 | {
370 | "cell_type": "code",
371 | "execution_count": null,
372 | "metadata": {},
373 | "outputs": [],
374 | "source": []
375 | }
376 | ],
377 | "metadata": {
378 | "kernelspec": {
379 | "display_name": "C++14",
380 | "language": "C++14",
381 | "name": "xcpp14"
382 | },
383 | "language_info": {
384 | "codemirror_mode": "text/x-c++src",
385 | "file_extension": ".cpp",
386 | "mimetype": "text/x-c++src",
387 | "name": "c++",
388 | "version": "-std=c++14"
389 | }
390 | },
391 | "nbformat": 4,
392 | "nbformat_minor": 2
393 | }
394 |
--------------------------------------------------------------------------------
/MathematicalBackground.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Mathematical Background\n",
8 | "- https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/MathpreIntro.html\n",
9 | "- library provides a lot of mathematical functions used in this chapter and beyond\n",
10 | " - http://www.cplusplus.com/reference/cmath/\n",
11 | "\n",
12 | "## Table of Contents\n",
13 | "- **[Introduction](#intro)**
\n",
14 | "- **[Sets & Relations](#sets)**
\n",
15 | "- **[Terms & Definitions](#defs)**
"
16 | ]
17 | },
18 | {
19 | "cell_type": "markdown",
20 | "metadata": {},
21 | "source": [
22 | ""
23 | ]
24 | },
25 | {
26 | "cell_type": "markdown",
27 | "metadata": {},
28 | "source": [
29 | "## Introduction\n",
30 | "- review and reference materials for mathematical notation, background, and techniques used in data structures and algorithm concepts\n",
31 | "\n",
32 | "- **Estimation** \n",
33 | " - not a mathematical technique\n",
34 | " - general engineering skill enormously useful to computer scientists doing design work\n",
35 | " - discard immediately any proposed solution whose estimated resource requirements fall well outside the problem's resource constraints \n",
36 | " - allow time for greater analysis of more promising solutions"
37 | ]
38 | },
39 | {
40 | "cell_type": "markdown",
41 | "metadata": {},
42 | "source": [
43 | ""
44 | ]
45 | },
46 | {
47 | "cell_type": "markdown",
48 | "metadata": {},
49 | "source": [
50 | "## Sets and Relations\n",
51 | "- mathematical set has wide application in computer science\n",
52 | "- notations and techniques of set theory are commonly used when describing and implementing algorithms\n",
53 | "\n",
54 | "### set\n",
55 | "- a collection of distinguishable/unique **members** or **elements**\n",
56 | "- no concept of order\n",
57 | "- each member of a set is either a **primitive element** of some base type or is a set itself\n",
58 | "- each value from the base type is either in the set or not in the set\n",
59 | "- E.g., a set P may have three integers 7, 11, and 42 which are members of set P with the base type integer\n",
60 | "\n",
61 | "### set relationships\n",
62 | "\n",
63 | "| Notation | Description |\n",
64 | "| --- | --- |\n",
65 | "|{1, 4} | set composed of the members 1 and 4 |\n",
66 | "| {𝗑\\|𝗑 is a positive integer} | A set definition using a set former E.g: the set of all positive integers |\n",
67 | "| $𝗑 \\in P$ | $𝗑$ is a member of set $P$ |\n",
68 | "| $𝗑 ∉ P$ | $𝗑$ is not a member of set $P$ |\n",
69 | "| $∅$ | The null or empty set |\n",
70 | "| $|P|$| Cardinality: size of set $P$ or number of members for set $P$ |\n",
71 | "| $P \\subseteq Q$, $Q \\supseteq P$ | Set $P$ is included in set $Q$
set P is a subset of set Q
Set $Q$ is a superset of set $P$ |\n",
72 | "| $P \\cup Q$ | Set Union: all elements appearing in $P$ OR $Q$ |\n",
73 | "| $P \\cap Q$ | Set Intersection: all elements appearing in $P$ AND $Q$ |\n",
74 | "| $P−Q$ | Set difference: all elements of set $P$ NOT in set $Q$ |\n",
75 | "| $P \\times Q$ | Set (Cartesian) Product: yields a set of ordered pairs |"
76 | ]
77 | },
78 | {
79 | "cell_type": "markdown",
80 | "metadata": {},
81 | "source": [
82 | "### examples\n",
83 | "Let's say we've two sets $P$ & $Q$ defined as:\n",
84 | "\n",
85 | "$P = \\{2, 3, 5\\} , Q = \\{5, 10\\}$\n",
86 | "\n",
87 | "Then,\n",
88 | "\n",
89 | "1. $|P| = ?$\n",
90 | "- $P \\cap Q = ?$\n",
91 | "- $P \\cup Q = ?$\n",
92 | "- $P - Q = ?$\n",
93 | "- $Q - P = ?$\n",
94 | "- $P \\times Q = \\{(2, 5), (2, 10), (3, 5), (3, 10), (5, 5), (5, 10)\\}$\n",
95 | "- **powerset** of $P$ (denoted by $2^P$) - the set of all possible subsets of $P$\n",
96 | " - = {∅, {2}, {3}, {5}, {2, 3}, {2, 5}, {3, 5}, {2, 3, 5}}"
97 | ]
98 | },
99 | {
100 | "cell_type": "markdown",
101 | "metadata": {},
102 | "source": [
103 | ""
104 | ]
105 | },
106 | {
107 | "cell_type": "markdown",
108 | "metadata": {},
109 | "source": [
110 | "## Terms & Definitions\n",
111 | "\n",
112 | "**bag** : a collection of elements with no order (like a set), but with duplicate-valued elements\n",
113 | "- usually represented using [ ]\n",
114 | "- e.g., [3, 4, 5, 4] is distinct from bag [3, 4, 5]\n",
115 | "\n",
116 | "**sequence** : a collection of elements with an order which may contain duplicate elements\n",
117 | "- also called **tuple** or **vector**\n",
118 | "\n",
119 | "**Factorial function** : written $n!$ is the product of the integers between $1$ and $n$\n",
120 | "- factorial function grows quickly as $n$ becomes larger\n",
121 | "- Stirling's approximation provides a good approximation\n",
122 | " - $n! \\approx \\sqrt{2\\pi n}(\\frac{n}{e})^n$, where $e \\approx 2.71828$\n",
123 | " - $e$ is the base for the system of natural logarithms\n",
124 | " - $n!$ grows slower than $n^n$ but it grows faster than $c^n$, for positive constant $c$ \n",
125 | "\n",
126 | "**Permutations** : permutation of sequence $S$ is simply the members of $S$ arranged in some order without repeating elements\n",
127 | "- if a sequence $S$ contains $n$ distinct members, then there are $n!$ different permutations for the sequence\n",
128 | "- to obtain a **random permutation** for a sequence is given below"
129 | ]
130 | },
131 | {
132 | "cell_type": "code",
133 | "execution_count": 2,
134 | "metadata": {},
135 | "outputs": [],
136 | "source": [
137 | "// include libraries\n",
138 | "#include \n",
139 | "#include \n",
140 | "#include \n",
141 | "#include \n",
142 | "#include \n",
143 | "using namespace std;"
144 | ]
145 | },
146 | {
147 | "cell_type": "code",
148 | "execution_count": 2,
149 | "metadata": {},
150 | "outputs": [],
151 | "source": [
152 | "// Randomly permute the valus in an int array\n",
153 | "void permute(int A[], int length) {\n",
154 | " // initialize random seed\n",
155 | " srand(time(NULL));\n",
156 | " //int length = sizeof(A)/sizeof(int);\n",
157 | " for(int i=0; i < length-1; i++) {\n",
158 | " int randIndex = rand()%length;\n",
159 | " //cout << randIndex << endl;\n",
160 | " std::swap(A[i], A[randIndex]); \n",
161 | " }\n",
162 | "}"
163 | ]
164 | },
165 | {
166 | "cell_type": "code",
167 | "execution_count": 3,
168 | "metadata": {},
169 | "outputs": [],
170 | "source": [
171 | "int arr[] = {1, 2, 3, 4, 5};"
172 | ]
173 | },
174 | {
175 | "cell_type": "code",
176 | "execution_count": 6,
177 | "metadata": {},
178 | "outputs": [],
179 | "source": [
180 | "permute(arr, 5);"
181 | ]
182 | },
183 | {
184 | "cell_type": "code",
185 | "execution_count": 7,
186 | "metadata": {},
187 | "outputs": [
188 | {
189 | "data": {
190 | "text/plain": [
191 | "{ 4, 3, 5, 1, 2 }"
192 | ]
193 | },
194 | "execution_count": 7,
195 | "metadata": {},
196 | "output_type": "execute_result"
197 | }
198 | ],
199 | "source": [
200 | "arr"
201 | ]
202 | },
203 | {
204 | "cell_type": "markdown",
205 | "metadata": {},
206 | "source": [
207 | "### Permutations vs Combinations\n",
208 | "- \"what's your locker combination?\" is technically wrong!\n",
209 | "- should be \"what's your locker permutation?\"\n",
210 | "- with permutations we care about the order of the elements, whereas with combinations we don't\n",
211 | "- e.g., locker combo of 3124 is not the same as 1234\n",
212 | "- if we there are $n$ objects and we want to choose $k$ of them, the total number of permutations is given by:\n",
213 | "\n",
214 | "$\\lgroup ^n _k \\rgroup = P_k^n = \\frac{n!}{(n-k)!}$\n",
215 | "\n",
216 | "- if there are $n$ objects and we want to choose $k$ of them, the total number of combinations is given by:\n",
217 | "\n",
218 | "$\\lgroup ^n _k \\rgroup = C_k^n = \\frac{n!}{k!(n-k)!}$\n",
219 | "\n",
220 | "### Boolean variables\n",
221 | "- variables that take on one of the two values `True` or `False`\n",
222 | " - also associated with the values $1$ and $0$, respectively\n",
223 | "\n",
224 | "### Boolean Logic Notation\n",
225 | "\n",
226 | "| Boolean logic | Meaning |\n",
227 | "| --- | --- |\n",
228 | "| $ A \\Rightarrow B$ | $A$ implies $B$ |\n",
229 | "| $ A \\Leftrightarrow B$ | $A$ if and only if $B$ |\n",
230 | "| $ A \\vee B$ | $A$ or $B$ |\n",
231 | "| $ A \\wedge B$ | $A$ and $B$|\n",
232 | "| $ \\sim A$ | not $A$ |\n",
233 | "\n",
234 | "### Floor and Ceiling functions\n",
235 | "- floor of $X$ (written $\\lfloor x\\rfloor$) returns rounded down value $\\le x$\n",
236 | " - $\\lfloor 3.4 \\rfloor$ = ?\n",
237 | " - $\\lfloor -3.4 \\rfloor$ = ?\n",
238 | "- ceiling of $x$ (written $\\lceil x \\rceil$) returns the rounded up value $\\ge x$\n",
239 | " - $\\lceil 3.4 \\rceil$ = ?\n",
240 | " - $\\lceil -3.4 \\rceil$ = ?\n",
241 | " "
242 | ]
243 | },
244 | {
245 | "cell_type": "code",
246 | "execution_count": 8,
247 | "metadata": {},
248 | "outputs": [
249 | {
250 | "name": "stdout",
251 | "output_type": "stream",
252 | "text": [
253 | "floor of 3.4 = 3\n",
254 | "floor of -3.4 = -4\n"
255 | ]
256 | }
257 | ],
258 | "source": [
259 | "// floor returns rounded down float value\n",
260 | "cout << \"floor of 3.4 = \" << floor(3.4) << endl;\n",
261 | "cout << \"floor of -3.4 = \" << floor(-3.4) << endl;"
262 | ]
263 | },
264 | {
265 | "cell_type": "code",
266 | "execution_count": 9,
267 | "metadata": {},
268 | "outputs": [
269 | {
270 | "name": "stdout",
271 | "output_type": "stream",
272 | "text": [
273 | "ceiling of of 3.4 = 4\n",
274 | "ceiling of -3.4 = -3\n"
275 | ]
276 | }
277 | ],
278 | "source": [
279 | "// floor returns rounded down float value\n",
280 | "cout << \"ceiling of of 3.4 = \" << ceil(3.4) << endl;\n",
281 | "cout << \"ceiling of -3.4 = \" << ceil(-3.4) << endl;"
282 | ]
283 | },
284 | {
285 | "cell_type": "markdown",
286 | "metadata": {},
287 | "source": [
288 | "### Modulus function (mod)\n",
289 | "- returns the remainder of an integer division\n",
290 | "- $n$ mod $m$ is calculated using $n\\%m$\n",
291 | " - $5\\%5$ = ?\n",
292 | " - $5\\%3$ = ?\n",
293 | " - $5\\%7$ = ?\n",
294 | "- $%$ is normally used to find a valid index between $0$ and $n-1$\n",
295 | " - used by many **hash systems** to find a valid index into the hash table"
296 | ]
297 | },
298 | {
299 | "cell_type": "code",
300 | "execution_count": 10,
301 | "metadata": {},
302 | "outputs": [
303 | {
304 | "name": "stdout",
305 | "output_type": "stream",
306 | "text": [
307 | "5%3 = 2\n",
308 | "5%5 = 0\n",
309 | "5%7 = 5\n"
310 | ]
311 | }
312 | ],
313 | "source": [
314 | "cout << \"5%3 = \" << 5%3 << endl;\n",
315 | "cout << \"5%5 = \" << 5%5 << endl;\n",
316 | "cout << \"5%7 = \" << 5%7 << endl;"
317 | ]
318 | },
319 | {
320 | "cell_type": "markdown",
321 | "metadata": {},
322 | "source": [
323 | "### Logarithms\n",
324 | "- logarithms are frequently used by programmers esp. $log_2$\n",
325 | "- the logarithm of base $b$ for value $y$ is the power to which $b$ is raised to get $y$\n",
326 | "- i.e. if $log_by = x$, then $b^x = y$, and $b^{log_by} = y$\n",
327 | "\n",
328 | "**Exercise**: What is the minimum number of bits needed to represent $1000$ distinct code values?\n",
329 | "- $\\lceil log_2 1000\\rceil$ = ?"
330 | ]
331 | },
332 | {
333 | "cell_type": "code",
334 | "execution_count": 11,
335 | "metadata": {},
336 | "outputs": [
337 | {
338 | "name": "stdout",
339 | "output_type": "stream",
340 | "text": [
341 | "answer = 10\n"
342 | ]
343 | }
344 | ],
345 | "source": [
346 | "#include \n",
347 | "cout << \"answer = \" << ceil(log2(1000)) << endl;"
348 | ]
349 | },
350 | {
351 | "cell_type": "markdown",
352 | "metadata": {},
353 | "source": [
354 | "- in CS, majority of data structures (DS) and algorithms use base of two\n",
355 | " - because DS and algorithms most often divide things in half, or store codes with binary bits\n",
356 | " - in theory, it's a common practice to use simply $log$ to represent $log_2$\n",
357 | " - in C++, $log$ function is natural log $log_e$\n",
358 | " - $log_2$ and $log_{10}$ are spelled out for base 2 and 10 respectively\n",
359 | " \n",
360 | "### Common logarithm properties\n",
361 | "1. $log(nm) = log(n) + log(m)$\n",
362 | "- $log(n/m) = log(n) - log(m)$\n",
363 | "- $log(n^r) = r log (n)$\n",
364 | "- $log_an = \\frac{log_bn}{log_ba}$\n",
365 | "\n",
366 | "- useful identity to know: $2^{log_2n} = n$"
367 | ]
368 | },
369 | {
370 | "cell_type": "code",
371 | "execution_count": 4,
372 | "metadata": {},
373 | "outputs": [],
374 | "source": [
375 | "int n = 16, m = 8;"
376 | ]
377 | },
378 | {
379 | "cell_type": "code",
380 | "execution_count": 6,
381 | "metadata": {},
382 | "outputs": [
383 | {
384 | "name": "stdout",
385 | "output_type": "stream",
386 | "text": [
387 | "n = 16 and m = 8\n",
388 | "log2(n*m) = 7 == 7\n",
389 | "log2(n/m) = 1 == 1\n",
390 | "log2(n^m) = 32 == 32\n",
391 | "log2(n) = 4 == 4\n",
392 | "2^(log2(n)) = 16 == 16\n"
393 | ]
394 | }
395 | ],
396 | "source": [
397 | "// examples\n",
398 | "cout << \"n = \" << n << \" and m = \" << m << endl;\n",
399 | "cout << \"log2(n*m) = \" << log2(n*m) << \" == \" << log2(n) + log2(m) << endl;\n",
400 | "cout << \"log2(n/m) = \" << log2(n/m) << \" == \" << log2(n) - log2(m) << endl;\n",
401 | "cout << \"log2(n^m) = \" << log2(pow(n, m)) << \" == \" << m*log2(n) << endl;\n",
402 | "cout << \"log2(n) = \" << log2(n) << \" == \" << log10(n)/log10(2) << endl;\n",
403 | "cout << \"2^(log2(n)) = \" << pow(2, log2(n)) << \" == \" << n << endl;"
404 | ]
405 | },
406 | {
407 | "cell_type": "markdown",
408 | "metadata": {},
409 | "source": [
410 | "### Summations\n",
411 | "- we typically apply some function over a range of values using loops and sum all the results called summation\n",
412 | "- typically written using \"Sigma\" notation: $\\sum_{i=1}^{n} f(i)$\n",
413 | " - summing the value of $f(i)$ over some range of integer values from $1$ to $n$\n",
414 | " - $f(1) + f(2) + f(3) + ... f(n)$\n",
415 | "- replacing summation with algebraic equation is known as closed-form solution making it easier to solve the summation\n",
416 | "- e.g., $\\sum_{i=1}^n 1$ = 1 + 1 + 1 +... = $n$ 1s = $n$\n",
417 | "- $\\sum_{i=1}^5i$ = ? (see animation here: https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/Summations.html)"
418 | ]
419 | },
420 | {
421 | "cell_type": "markdown",
422 | "metadata": {},
423 | "source": [
424 | "## Bit shifting\n",
425 | "- left shift (<<) and right shift (>>)\n",
426 | "- << (left shift) takes two numbers, left shifts the bits of the first operand by number of places to shift using second operand\n",
427 | "- in another words, left shifting an integer $x$ with an integer $y$ or $(x<>$ (right shift) takes two numbers, right shifts the bits of the first operand by number of places to shift using second operand\n",
463 | "- in another words, right shifting an integer $x$ with an integer $y$ or $(x>>y)$ is equivalent to dividing $x$ with $2^y$ ($2$ raise to power $y$)"
464 | ]
465 | },
466 | {
467 | "cell_type": "code",
468 | "execution_count": 17,
469 | "metadata": {},
470 | "outputs": [
471 | {
472 | "name": "stdout",
473 | "output_type": "stream",
474 | "text": [
475 | "x/2^1 = 512\n",
476 | "x/2^10 = 1\n"
477 | ]
478 | }
479 | ],
480 | "source": [
481 | "x = 1024;\n",
482 | "cout << \"x/2^1 = \" << (x>>1) << endl; // needs () to force the order of operation as bit shift not cout<<\n",
483 | "cout << \"x/2^10 = \" << (x>>10) << endl;"
484 | ]
485 | },
486 | {
487 | "cell_type": "markdown",
488 | "metadata": {},
489 | "source": [
490 | "## Exercises\n",
491 | "### Applications of combinations and permutations\n",
492 | "1. Integer Division - https://open.kattis.com/problems/integerdivision\n",
493 | " - unordered_map\n",
494 | "- A Towering Problem - https://open.kattis.com/problems/towering\n",
495 | "- Veci - https://open.kattis.com/problems/veci\n",
496 | "- Character Development - https://open.kattis.com/problems/character\n",
497 | "- Perica - https://open.kattis.com/problems/perica\n",
498 | "- An Industrial Spy - https://open.kattis.com/problems/industrialspy"
499 | ]
500 | },
501 | {
502 | "cell_type": "code",
503 | "execution_count": null,
504 | "metadata": {},
505 | "outputs": [],
506 | "source": []
507 | }
508 | ],
509 | "metadata": {
510 | "kernelspec": {
511 | "display_name": "C++14",
512 | "language": "C++14",
513 | "name": "xcpp14"
514 | },
515 | "language_info": {
516 | "codemirror_mode": "text/x-c++src",
517 | "file_extension": ".cpp",
518 | "mimetype": "text/x-c++src",
519 | "name": "c++",
520 | "version": "14"
521 | }
522 | },
523 | "nbformat": 4,
524 | "nbformat_minor": 4
525 | }
526 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Introduction to Algorithms using C++
3 |
4 | - Jupyter notebooks for text **CS3 Data Structures and Algorithms:** https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/
5 |
6 | ## View the notebooks online at [nbviewer.jupyter.org](https://nbviewer.jupyter.org/github/rambasnet/CS3Notebooks/tree/master/)
7 |
8 | - github itself renders notebooks most of the time but not reliable and some contents may not render correctly
9 | - click the above link or go to nbviewer.jupyter.org and copy pase this github repo URL
10 | - NOTE: You can only read text and code but not execute it online
11 | - see instructions below to run these notebooks (C++ code) on your system
12 |
13 | ## Run C++ Code in Notebooks
14 | ### Requirements
15 | - Jupyter Notebook
16 | - xeus-cling Notebook Kernel (C++ interpreter)
17 |
18 | ## Install Required Tools
19 | ### Linux/Mac
20 | - Download and install Miniconda: https://conda.io/miniconda.html
21 | - download Miniconda3...sh shell script installer file
22 | - open a terminal cd into the directory where the file was downloaded
23 | - run the shell script installer file
24 | ```
25 | $ bash Miniconda3.....sh
26 | ```
27 | - go through installation process; default works great on every prompt
28 | - once conda is installed; use conda to install the following pacakages
29 | - you have to close and start a new terminal to run freshly installed conda
30 | ```
31 | $ conda create -n cpp #create virtual environment for C++
32 | $ conda activate cpp
33 | $ conda install notebook
34 | $ conda install -c conda-forge xeus-cling
35 | $ conda install -c conda-forge jupyter_contrib_nbextensions
36 | $ conda install -c conda-forge jupyter_nbextensions_configurator
37 | $ jupyter nbextensions_configurator enable --user
38 | ```
39 |
40 | ### Windows
41 | - On Windows, follow the instruction here: https://github.com/QuantStack/xeus-cling
42 | to install xeus-cling
43 | - NOTE: C++ interpreter kernel is experimental on Windows
44 | - Recommended:
45 | - enable and use WSL (Ubuntu) on Windows 10
46 | - follow Linux/Mac instructions above
47 |
48 |
49 | ## Run Notebooks
50 | - open a terminal and cd into this cloned/downloaded repository folder and run jupyter notebook
51 | ```
52 | $ cd
53 | $ conda activate cpp
54 | $ jupyter notebook
55 | ```
56 | - start from 00-TableOfContents.ipynb chapter or open any chapter
57 |
58 | ## Stop Jupyter Notebook server
59 |
60 | - enter `ctrl+c` simultaneously on the Terminal where the jupyter notebook server is running on
61 |
62 | ```bash
63 | $ conda deactivate # to deactivate cpp env and go to base env
64 | ```
65 |
66 |
--------------------------------------------------------------------------------
/SearchAlgorithms.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Search Algorithms\n",
8 | "\n",
9 | "## Table of Contents\n",
10 | "- **[Sequential Search](#linear)**
\n",
11 | "- **[Sequential Search Asymptotic Analysis](#linearanalysis)**
\n",
12 | "- **[Binary Search](#binary)**
\n",
13 | "- **[Binary Search Asymptotic Analysis](#binaryanalysis)**
\n",
14 | "- **[Sequential Search vs Binary Search Empirical Analysis](#empirical)**
\n"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | "## header includes required for this notebook"
22 | ]
23 | },
24 | {
25 | "cell_type": "code",
26 | "execution_count": 1,
27 | "metadata": {},
28 | "outputs": [],
29 | "source": [
30 | "#include \n",
31 | "#include \n",
32 | "#include \n",
33 | "#include \n",
34 | "#include \n",
35 | "#include \n",
36 | "#include \n",
37 | "\n",
38 | "using namespace std;"
39 | ]
40 | },
41 | {
42 | "cell_type": "code",
43 | "execution_count": 2,
44 | "metadata": {},
45 | "outputs": [],
46 | "source": [
47 | "// operator<< overloaded to print a vector\n",
48 | "template\n",
49 | "ostream& operator<<(ostream& out, const vector& v) {\n",
50 | " char comma[3] = {'\\0', ' ', '\\0'};\n",
51 | " out << '[';\n",
52 | " for (auto& e: v) {\n",
53 | " out << comma << e;\n",
54 | " comma[0] = ',';\n",
55 | " }\n",
56 | " out << \"]\";\n",
57 | " return out;\n",
58 | "}"
59 | ]
60 | },
61 | {
62 | "cell_type": "markdown",
63 | "metadata": {},
64 | "source": [
65 | "## Sequential Search\n",
66 | "- find a key in a sequence container\n",
67 | "- input is unsorted vector\n",
68 | "- output is the index if key found, -1 if key not found\n",
69 | "- Algorithm:\n",
70 | " 1. start from the first index\n",
71 | " 2. if the key matches with the element at the index, return index\n",
72 | " 3. otherwise move to the next element (index)\n",
73 | " 4. repeat from step 2\n",
74 | " 5. if key doesn't match with any of the element, return -1"
75 | ]
76 | },
77 | {
78 | "cell_type": "code",
79 | "execution_count": 3,
80 | "metadata": {},
81 | "outputs": [],
82 | "source": [
83 | "template\n",
84 | "int sequentialSearch(const vector & v, T key) {\n",
85 | " int index = 0;\n",
86 | " while (index < v.size()) {\n",
87 | " if (v[index] == key) // found our element; key comparison that controls the loop\n",
88 | " return index;\n",
89 | " else\n",
90 | " index ++;\n",
91 | " }\n",
92 | " return -1;\n",
93 | "}"
94 | ]
95 | },
96 | {
97 | "cell_type": "code",
98 | "execution_count": 4,
99 | "metadata": {},
100 | "outputs": [],
101 | "source": [
102 | "void generateRandomNumbers(vector &rands, int start, int end) {\n",
103 | " // fill the vectors with random numbers\n",
104 | " random_device rd;\n",
105 | " //https://en.cppreference.com/w/cpp/numeric/random/mersenne_twister_engine\n",
106 | " // generates high quality random unsigned ints\n",
107 | " mt19937 mt(rd());\n",
108 | " uniform_int_distribution<> dis(start, end); // numbers between start and end inclusive\n",
109 | " generate(rands.begin(), rands.end(), bind(dis, ref(mt)));\n",
110 | "}"
111 | ]
112 | },
113 | {
114 | "cell_type": "code",
115 | "execution_count": 5,
116 | "metadata": {},
117 | "outputs": [],
118 | "source": [
119 | "vector nums(20);"
120 | ]
121 | },
122 | {
123 | "cell_type": "code",
124 | "execution_count": 6,
125 | "metadata": {},
126 | "outputs": [
127 | {
128 | "name": "stdout",
129 | "output_type": "stream",
130 | "text": [
131 | "[5, 6, 12, 2, 0, 18, 14, 14, 17, 4, 5, 16, 20, 9, 4, 10, 11, 5, 14, 15]\n"
132 | ]
133 | }
134 | ],
135 | "source": [
136 | "generateRandomNumbers(nums, 0, 20);\n",
137 | "cout << nums << endl;"
138 | ]
139 | },
140 | {
141 | "cell_type": "code",
142 | "execution_count": 7,
143 | "metadata": {},
144 | "outputs": [],
145 | "source": [
146 | "int key;\n",
147 | "int searchIndex;"
148 | ]
149 | },
150 | {
151 | "cell_type": "code",
152 | "execution_count": 14,
153 | "metadata": {},
154 | "outputs": [],
155 | "source": [
156 | "// generate a random number and search in nums vector...\n",
157 | "srand(time(NULL));\n",
158 | "key = rand()%20;"
159 | ]
160 | },
161 | {
162 | "cell_type": "code",
163 | "execution_count": 15,
164 | "metadata": {},
165 | "outputs": [
166 | {
167 | "name": "stdout",
168 | "output_type": "stream",
169 | "text": [
170 | "17 found at index 8\n"
171 | ]
172 | }
173 | ],
174 | "source": [
175 | "searchIndex = sequentialSearch(nums, key);\n",
176 | "if (searchIndex >= 0)\n",
177 | " cout << key << \" found at index \" << searchIndex << endl;\n",
178 | "else\n",
179 | " cout << key << \" not found!\" << endl;"
180 | ]
181 | },
182 | {
183 | "cell_type": "markdown",
184 | "metadata": {},
185 | "source": [
186 | ""
187 | ]
188 | },
189 | {
190 | "cell_type": "markdown",
191 | "metadata": {},
192 | "source": [
193 | "## Sequential Search Asymptotic Analysis\n",
194 | "- look for key comparison/operation\n",
195 | "- Best case: $1$ comparison, $O(1)$\n",
196 | "- Average case: $ \\frac n 2$ key comparisons\n",
197 | " - $T(n) = c_s\\times \\frac n 2$\n",
198 | " - for all values of $ n > 1, c_s \\times \\frac n 2 \\leq c_s \\times n$\n",
199 | " - therefore, by the Big O definition, $T(n)$ is in $O(n)$ for $n_0 = 1$ and $c = c_s$\n",
200 | "- Worst case: $n$ comparison, $O(n)$"
201 | ]
202 | },
203 | {
204 | "cell_type": "markdown",
205 | "metadata": {},
206 | "source": [
207 | ""
208 | ]
209 | },
210 | {
211 | "cell_type": "markdown",
212 | "metadata": {},
213 | "source": [
214 | "## Binary Search\n",
215 | "- input is a sequence sorted in increasing order\n",
216 | "- imagine searching for a word in a dictionary or someone's name in a phone directory\n",
217 | "- uses divide and conquer technique\n",
218 | " - in each iteration, the search space is reduced by half\n",
219 | " - if key is found at the middle, return the index\n",
220 | " - repeat the search in lower or upper half of the sequence until sequence is exhausted\n",
221 | "- visualize binary search: https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/AnalProgram.html"
222 | ]
223 | },
224 | {
225 | "cell_type": "code",
226 | "execution_count": 16,
227 | "metadata": {},
228 | "outputs": [],
229 | "source": [
230 | "template \n",
231 | "int binarySearch(const vector &v, T key) {\n",
232 | " int low = 0;\n",
233 | " int high = v.size()-1;\n",
234 | " while (low <= high) { // stop when low and high cross\n",
235 | " int mid = (low+high)/2; // check middle of sequence\n",
236 | " if (v[mid] == key) // found it\n",
237 | " return mid; // return the index\n",
238 | " else if (v[mid] > key) // check in left half\n",
239 | " high = mid - 1;\n",
240 | " else // check in right half\n",
241 | " low = mid + 1;\n",
242 | " }\n",
243 | " return -1;\n",
244 | "}"
245 | ]
246 | },
247 | {
248 | "cell_type": "code",
249 | "execution_count": 17,
250 | "metadata": {},
251 | "outputs": [],
252 | "source": [
253 | "vector nums1(20);"
254 | ]
255 | },
256 | {
257 | "cell_type": "code",
258 | "execution_count": 18,
259 | "metadata": {},
260 | "outputs": [
261 | {
262 | "name": "stdout",
263 | "output_type": "stream",
264 | "text": [
265 | "[4, 5, 8, 11, 17, 6, 10, 1, 12, 5, 7, 14, 13, 10, 11, 12, 16, 13, 20, 17]\n"
266 | ]
267 | }
268 | ],
269 | "source": [
270 | "generateRandomNumbers(nums1, 0, 20);\n",
271 | "cout << nums1 << endl;"
272 | ]
273 | },
274 | {
275 | "cell_type": "code",
276 | "execution_count": 19,
277 | "metadata": {},
278 | "outputs": [
279 | {
280 | "name": "stdout",
281 | "output_type": "stream",
282 | "text": [
283 | "[1, 4, 5, 5, 6, 7, 8, 10, 10, 11, 11, 12, 12, 13, 13, 14, 16, 17, 17, 20]\n"
284 | ]
285 | }
286 | ],
287 | "source": [
288 | "// for binary search to work, sequence must be sorted\n",
289 | "sort(nums1.begin(), nums1.end());\n",
290 | "cout << nums1 << endl;"
291 | ]
292 | },
293 | {
294 | "cell_type": "code",
295 | "execution_count": 24,
296 | "metadata": {},
297 | "outputs": [
298 | {
299 | "name": "stdout",
300 | "output_type": "stream",
301 | "text": [
302 | " key to search = 5\n"
303 | ]
304 | }
305 | ],
306 | "source": [
307 | "// generate a random number and search in nums1 vector...\n",
308 | "srand(time(NULL));\n",
309 | "key = rand()%20;\n",
310 | "cout << \" key to search = \" << key << endl;"
311 | ]
312 | },
313 | {
314 | "cell_type": "code",
315 | "execution_count": 25,
316 | "metadata": {},
317 | "outputs": [
318 | {
319 | "name": "stdout",
320 | "output_type": "stream",
321 | "text": [
322 | "5 found at index 2\n"
323 | ]
324 | }
325 | ],
326 | "source": [
327 | "searchIndex = binarySearch(nums1, key);\n",
328 | "if (searchIndex >= 0)\n",
329 | " cout << key << \" found at index \" << searchIndex << endl;\n",
330 | "else\n",
331 | " cout << key << \" not found!\" << endl;"
332 | ]
333 | },
334 | {
335 | "cell_type": "markdown",
336 | "metadata": {},
337 | "source": [
338 | ""
339 | ]
340 | },
341 | {
342 | "cell_type": "markdown",
343 | "metadata": {},
344 | "source": [
345 | "## Binary Search Asymptotic Analysis\n",
346 | "- Best case: $1$ comparison $O(1)$\n",
347 | "- Average and Worst cases: $(O(logn))$\n",
348 | "- binary search analysis visualization: https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/AnalProgram.html\n",
349 | "- each loop of binarySearch cuts the size of the sequence (problem size) approximately in half and for each problem size, we do $O(1)$ comparison for a total of $\\sum_{i=0}^{log n}1$"
350 | ]
351 | },
352 | {
353 | "cell_type": "markdown",
354 | "metadata": {},
355 | "source": [
356 | "### Which one is more efficient?\n",
357 | "- as $n$ grows, the $O(n)$ running time for sequential search in the average and worst cases quickly becomes much larger than the $O(log n)$ of binary search\n",
358 | "\n",
359 | "### What's the caveat?\n",
360 | "- binary search is more efficient iff the data is in sorted order\n",
361 | "- is it worth sorting the data?\n",
362 | " - depends how often, one will have to do the search on the data"
363 | ]
364 | },
365 | {
366 | "cell_type": "markdown",
367 | "metadata": {},
368 | "source": [
369 | ""
370 | ]
371 | },
372 | {
373 | "cell_type": "markdown",
374 | "metadata": {},
375 | "source": [
376 | "## Empirical Analysis: Linear Search Vs Binary Search"
377 | ]
378 | },
379 | {
380 | "cell_type": "code",
381 | "execution_count": 26,
382 | "metadata": {},
383 | "outputs": [],
384 | "source": [
385 | "// function to time sequentialSearch and binarySearch\n",
386 | "double timeit(const vector &v, int key, int (*searchFunc)(const vector &, int)) {\n",
387 | " clock_t begin = clock();\n",
388 | " int i = (*searchFunc)(v, key);\n",
389 | " clock_t end = clock();\n",
390 | " double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;\n",
391 | " return elapsed_secs;\n",
392 | "}"
393 | ]
394 | },
395 | {
396 | "cell_type": "code",
397 | "execution_count": 27,
398 | "metadata": {},
399 | "outputs": [],
400 | "source": [
401 | "void compareSearchAlgos(int N) {\n",
402 | " vector nums(N);\n",
403 | " generateRandomNumbers(nums, 0, N);\n",
404 | " // make a copy of nums\n",
405 | " vector sortedNums = nums;\n",
406 | " sort(sortedNums.begin(), sortedNums.end());\n",
407 | " // generate a random number and search in nums1 vector...\n",
408 | " srand(time(NULL));\n",
409 | " int key = rand()%N+1;\n",
410 | " cout << \"key to search = \" << key << endl;\n",
411 | " cout << \"Sequential Search time: \" << timeit(nums, key, sequentialSearch) << \" seconds.\" << endl;\n",
412 | " cout << \"Binary Search time: \" << timeit(sortedNums, key, binarySearch) << \" seconds.\" << endl;\n",
413 | "}"
414 | ]
415 | },
416 | {
417 | "cell_type": "markdown",
418 | "metadata": {},
419 | "source": [
420 | "### Sequential and Binary Search Comparison with 100 K integers"
421 | ]
422 | },
423 | {
424 | "cell_type": "code",
425 | "execution_count": 29,
426 | "metadata": {},
427 | "outputs": [
428 | {
429 | "name": "stdout",
430 | "output_type": "stream",
431 | "text": [
432 | "key to search = 83\n",
433 | "Sequential Search time: 8e-06 seconds.\n",
434 | "Binary Search time: 2e-06 seconds.\n"
435 | ]
436 | }
437 | ],
438 | "source": [
439 | "compareSearchAlgos(100);"
440 | ]
441 | },
442 | {
443 | "cell_type": "markdown",
444 | "metadata": {},
445 | "source": [
446 | "### Sequential and Binary Search Comparison with 1 M integers"
447 | ]
448 | },
449 | {
450 | "cell_type": "code",
451 | "execution_count": 30,
452 | "metadata": {},
453 | "outputs": [
454 | {
455 | "name": "stdout",
456 | "output_type": "stream",
457 | "text": [
458 | "key to search = 589446\n",
459 | "Sequential Search time: 0.001318 seconds.\n",
460 | "Binary Search time: 2e-05 seconds.\n"
461 | ]
462 | }
463 | ],
464 | "source": [
465 | "compareSearchAlgos(1000000);"
466 | ]
467 | },
468 | {
469 | "cell_type": "markdown",
470 | "metadata": {},
471 | "source": [
472 | "### Sequential and Binary Search Comparison with 1 B integers"
473 | ]
474 | },
475 | {
476 | "cell_type": "code",
477 | "execution_count": 31,
478 | "metadata": {},
479 | "outputs": [
480 | {
481 | "name": "stdout",
482 | "output_type": "stream",
483 | "text": [
484 | "key to search = 111883618\n",
485 | "Sequential Search time: 0.018164 seconds.\n",
486 | "Binary Search time: 1e-05 seconds.\n"
487 | ]
488 | }
489 | ],
490 | "source": [
491 | "compareSearchAlgos(1000000000);\n",
492 | "/*\n",
493 | "// sorting took much longer!\n",
494 | "key to search = 505016941\n",
495 | "Sequential Search time: 2.88439 seconds\n",
496 | "Binary Search time: 4e-05 seconds\n",
497 | "*/"
498 | ]
499 | },
500 | {
501 | "cell_type": "code",
502 | "execution_count": null,
503 | "metadata": {},
504 | "outputs": [],
505 | "source": []
506 | }
507 | ],
508 | "metadata": {
509 | "kernelspec": {
510 | "display_name": "C++14",
511 | "language": "C++14",
512 | "name": "xcpp14"
513 | },
514 | "language_info": {
515 | "codemirror_mode": "text/x-c++src",
516 | "file_extension": ".cpp",
517 | "mimetype": "text/x-c++src",
518 | "name": "c++",
519 | "version": "14"
520 | }
521 | },
522 | "nbformat": 4,
523 | "nbformat_minor": 2
524 | }
525 |
--------------------------------------------------------------------------------
/SpanningTreesPrims.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Minimal Cost Spanning Trees (MST)\n",
8 | "https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/MCST.html\n",
9 | "\n",
10 | "### Table of Contents\n",
11 | "- **[MST Problems](#problems)**
\n",
12 | "- **[Prim's Algorithm](#prims)**
\n",
13 | "- **[Kruskal's Algorithm](MSTKruskals.ipynb)**
"
14 | ]
15 | },
16 | {
17 | "cell_type": "markdown",
18 | "metadata": {},
19 | "source": [
20 | "## Spanning Tree\n",
21 | "- spanning tree of a graph is a sub-graph that is a tree and connects all the vertices together\n",
22 | "- a graph can have many different spanning trees\n",
23 | "\n",
24 | "## MST Problems\n",
25 | "- given a connected, undirected weighted graph $G$, MST is the graph containing the vertices of $G$ along with the subset of $G$'s edges that:\n",
26 | " 1. has minimum total cost measured by summing the values for all of the edges in the subset\n",
27 | " 2. keeps all the vertices connected\n",
28 | "- some properties of MST\n",
29 | " 1. contains NO cycles\n",
30 | " 2. free tree with $|V|-1$ edges\n",
31 | " 3. the required set of edges forms a tree, it spans the vertices (i.e., connects them together)\n",
32 | " 4. has minimal cost (hence MST)\n",
33 | "- red edges indicated the subset making up the MST in the following tree\n",
34 | "- note that edge $(C, F)$ could be replaced with edge $(D, F)$ to form a different MST with equal cost\n",
35 | "
"
36 | ]
37 | },
38 | {
39 | "cell_type": "markdown",
40 | "metadata": {},
41 | "source": [
42 | "## MST Applications\n",
43 | "http://www.utdallas.edu/~besp/teaching/mst-applications.pdf\n",
44 | "- building a connected network (e.g., electrical grid, computer network, transportation networks, water supply networks) fully connected at the lowest cost\n",
45 | "- Artificial Intelligence (AI) application\n",
46 | " - clustering: grouping a bunch of points into k clusters\n",
47 | " - handwriting recognition\n",
48 | " - curvilinear feature extraction in computer vision\n",
49 | "- computer circuit design\n",
50 | "- traveling salesman problem (TSP) - given a list of cities and the distances between each pair of cities, what is the shortest possible route that visits each city and returns to the origin city?"
51 | ]
52 | },
53 | {
54 | "cell_type": "markdown",
55 | "metadata": {},
56 | "source": [
57 | "## Prim's Algorithm\n",
58 | "- Prim's algorithms for $MST$ is very similar to Dijkstra's SSSP algorithm\n",
59 | "- algorithm steps:\n",
60 | " 1. start with any vertex, $N$ in the graph, $MST$ is initially $N$\n",
61 | " 2. pick the least-cost edge connected to $N$ connecting to say $M$\n",
62 | " 3. $MST$ now has vertices $N$ and $M$ and edge $(N, M)$\n",
63 | " 4. pick the least-cost edge coming from current nodes in $MST$ to any other vertex\n",
64 | " 5. continue step 4 until all the nodes are in the $MST$\n",
65 | "\n",
66 | "- priority queue-based implementation is extremely similar to Dijkstra's algorithm except for updating the weight/distance of each vertex\n",
67 | "- the primary difference with Dijkstra's algorithm is that Prim's seeks not the next closest vertex to the start vertex, but rather the next closest vertex to any vertex currently in the $MST$\n",
68 | "- e.g. while exploring the unvisited neighbor node $v$ of $u$:\n",
69 | " - **Dijkstra's**:\n",
70 | " - minimimizes the tentative distance vector for each node from the source\n",
71 | " ```\n",
72 | " // update distance[v] if the distance[u] + weight of the edge between u->v is smaller than current distance[v]\n",
73 | " if (distance[v] > distance[u] + weightBetween(u, v))\n",
74 | " distance[v] = distance[u] + weightBetween(u, v)\n",
75 | " ```\n",
76 | " - **Prim's**:\n",
77 | " - minimizes the tentative weight vector for each node from the parent node\n",
78 | " ```\n",
79 | " // update weight[v] if the weight of edge between u->v is smaller than current weight[v]\n",
80 | " if (weight[v] > weightBetween(u, v))\n",
81 | " weight[v] = weightBetween(u, v)\n",
82 | " ```\n",
83 | " \n",
84 | "### visualize Prim's algorithm: https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/MCST.html"
85 | ]
86 | },
87 | {
88 | "cell_type": "markdown",
89 | "metadata": {},
90 | "source": [
91 | "### Implementation of Prim's algorithm using priority queue"
92 | ]
93 | },
94 | {
95 | "cell_type": "code",
96 | "execution_count": 1,
97 | "metadata": {},
98 | "outputs": [],
99 | "source": [
100 | "#include \n",
101 | "#include \n",
102 | "#include // priority_queue\n",
103 | "#include // make_pair\n",
104 | "#include \n",
105 | "#include // sizes of integral types\n",
106 | "#include \n",
107 | "\n",
108 | "using namespace std;\n",
109 | "using iPair = pair;"
110 | ]
111 | },
112 | {
113 | "cell_type": "code",
114 | "execution_count": 2,
115 | "metadata": {},
116 | "outputs": [],
117 | "source": [
118 | "// Prim's algorithm using priority_queue\n",
119 | "// finds and updates the MST - vector of parent node indices\n",
120 | "template\n",
121 | "void PrimsMST(T & G, vector & MST, int source) {\n",
122 | " // min priority_queue of vertices that need to be processed\n",
123 | " // stores pair of \n",
124 | " priority_queue, greater > pq;\n",
125 | " vector visited(G.nodeCount(), false);\n",
126 | " MST.resize(G.nodeCount());\n",
127 | " fill(MST.begin(), MST.end(), -1); //remembers parent or where each node is visited from\n",
128 | " vector weight(G.nodeCount(), INT_MAX); //initialize weigth vectors with INT_MAX\n",
129 | " weight[source] = 0; // weight of source\n",
130 | " pq.push({0, source}); // {weight, vertex}\n",
131 | " MST[source] = -1; // source node doesn't have a parent\n",
132 | " while (! pq.empty()) {\n",
133 | " int u = pq.top().second;\n",
134 | " pq.pop();\n",
135 | " visited[u] = true;\n",
136 | " for(int v: G.neighbors(u)) {\n",
137 | " if (visited[v]) continue;\n",
138 | " int w = G.getWeight(u, v);\n",
139 | " // if the weight from u to v is smaller than the previously known weight\n",
140 | " // update the weight\n",
141 | " if (w < weight[v]) {\n",
142 | " weight[v] = w;\n",
143 | " pq.push({w, v});\n",
144 | " MST[v] = u;\n",
145 | " }\n",
146 | " }\n",
147 | " }\n",
148 | "}"
149 | ]
150 | },
151 | {
152 | "cell_type": "markdown",
153 | "metadata": {},
154 | "source": [
155 | "## Test Prim's Algorithm\n",
156 | "- use adjacency matrix representation of graph\n",
157 | "- matrix representation is easier to quickly find the weight of the MST using indices"
158 | ]
159 | },
160 | {
161 | "cell_type": "code",
162 | "execution_count": 3,
163 | "metadata": {},
164 | "outputs": [],
165 | "source": [
166 | "class Graph {\n",
167 | " private:\n",
168 | " vector > graph;\n",
169 | " \n",
170 | " public:\n",
171 | " Graph(size_t n) {\n",
172 | " this->graph.assign(n, vector(n, 0));\n",
173 | " /*\n",
174 | " for (int i=0; i v(n, 0); \n",
176 | " //initialize to 0; means not connected\n",
177 | " graph.push_back(v);\n",
178 | " }\n",
179 | " */\n",
180 | " }\n",
181 | " \n",
182 | " // return the number of vertices/nodes\n",
183 | " size_t nodeCount() {\n",
184 | " return graph.size();\n",
185 | " }\n",
186 | " \n",
187 | " // add a new edge from node u to node v, with weight w\n",
188 | " void addEdge(int u, int v, int w) {\n",
189 | " graph[u][v] = w;\n",
190 | " }\n",
191 | "\n",
192 | " // returns vector of pairs containing neighbors weight\n",
193 | " vector neighbors(int u) {\n",
194 | " vector neighs;\n",
195 | " for(int v = 0; v < graph[u].size(); v++)\n",
196 | " if (graph[u][v] != 0) neighs.push_back(v);\n",
197 | " \n",
198 | " return neighs;\n",
199 | " }\n",
200 | " \n",
201 | " int getWeight(int u, int v) {\n",
202 | " return graph[u][v];\n",
203 | " }\n",
204 | "};"
205 | ]
206 | },
207 | {
208 | "cell_type": "markdown",
209 | "metadata": {},
210 | "source": [
211 | "Let's work with the following graph:\n",
212 | "
"
213 | ]
214 | },
215 | {
216 | "cell_type": "code",
217 | "execution_count": 4,
218 | "metadata": {},
219 | "outputs": [],
220 | "source": [
221 | "// represent undirected graph shown in above diagram\n",
222 | "// A->0, B->1, C->2, D->3, E->4, F->5\n",
223 | "Graph graph(6); // graph with 6 nodes 6x6 matrix\n",
224 | "vector MST; // store parent index"
225 | ]
226 | },
227 | {
228 | "cell_type": "code",
229 | "execution_count": 5,
230 | "metadata": {},
231 | "outputs": [],
232 | "source": [
233 | "// 16 bidirectional edges\n",
234 | "graph.addEdge(0, 2, 7);\n",
235 | "graph.addEdge(0, 4, 9);\n",
236 | "graph.addEdge(1, 2, 5);\n",
237 | "graph.addEdge(1, 5, 6);\n",
238 | "graph.addEdge(2, 0, 7);\n",
239 | "graph.addEdge(2, 3, 1);\n",
240 | "graph.addEdge(2, 5, 2);\n",
241 | "graph.addEdge(2, 1, 5);\n",
242 | "graph.addEdge(3, 2, 1);\n",
243 | "graph.addEdge(3, 5, 2);\n",
244 | "graph.addEdge(4, 0, 9);\n",
245 | "graph.addEdge(4, 6, 1);\n",
246 | "graph.addEdge(5, 1, 6);\n",
247 | "graph.addEdge(5, 2, 2);\n",
248 | "graph.addEdge(5, 3, 2);\n",
249 | "graph.addEdge(5, 4, 1);"
250 | ]
251 | },
252 | {
253 | "cell_type": "code",
254 | "execution_count": 6,
255 | "metadata": {},
256 | "outputs": [],
257 | "source": [
258 | "// function to print MST with corresponding weight\n",
259 | "void printMST(vector& MST, Graph& G) {\n",
260 | " int total = 0;\n",
261 | " cout << \"Edge\\t Weight\\n\";\n",
262 | " for (int i=0; i < G.nodeCount(); i++) {\n",
263 | " if (MST[i] == -1) // source node\n",
264 | " continue;\n",
265 | " total += G.getWeight(MST[i], i);\n",
266 | " cout << char(MST[i]+65) << \"->\" << char(i+65) << \"\\t = \" << G.getWeight(MST[i], i) << \"\\n\";\n",
267 | " }\n",
268 | " cout << \"Total Weight = \" << total << endl;\n",
269 | "}"
270 | ]
271 | },
272 | {
273 | "cell_type": "code",
274 | "execution_count": 7,
275 | "metadata": {},
276 | "outputs": [],
277 | "source": [
278 | "int source = 5;"
279 | ]
280 | },
281 | {
282 | "cell_type": "code",
283 | "execution_count": 8,
284 | "metadata": {},
285 | "outputs": [],
286 | "source": [
287 | " PrimsMST(graph, MST, source);"
288 | ]
289 | },
290 | {
291 | "cell_type": "code",
292 | "execution_count": 9,
293 | "metadata": {},
294 | "outputs": [
295 | {
296 | "name": "stdout",
297 | "output_type": "stream",
298 | "text": [
299 | "Edge\t Weight\n",
300 | "C->A\t = 7\n",
301 | "C->B\t = 5\n",
302 | "F->C\t = 2\n",
303 | "C->D\t = 1\n",
304 | "F->E\t = 1\n",
305 | "Total Weight = 16\n"
306 | ]
307 | }
308 | ],
309 | "source": [
310 | "printMST(MST, graph);"
311 | ]
312 | },
313 | {
314 | "cell_type": "code",
315 | "execution_count": 10,
316 | "metadata": {},
317 | "outputs": [],
318 | "source": [
319 | "// start from different source vertex\n",
320 | "source = 2;\n",
321 | "PrimsMST(graph, MST, source);"
322 | ]
323 | },
324 | {
325 | "cell_type": "code",
326 | "execution_count": 11,
327 | "metadata": {},
328 | "outputs": [
329 | {
330 | "name": "stdout",
331 | "output_type": "stream",
332 | "text": [
333 | "Edge\t Weight\n",
334 | "C->A\t = 7\n",
335 | "C->B\t = 5\n",
336 | "C->D\t = 1\n",
337 | "F->E\t = 1\n",
338 | "C->F\t = 2\n",
339 | "Total Weight = 16\n"
340 | ]
341 | }
342 | ],
343 | "source": [
344 | "printMST(MST, graph);"
345 | ]
346 | },
347 | {
348 | "cell_type": "markdown",
349 | "metadata": {},
350 | "source": [
351 | "## Time Complexity of Prim's Algorithm\n",
352 | "- priority queue-based implementation cost is exactly same as that of Dijkstra's\n",
353 | "- bulk of the cost comes from the loop which depends on the running time of priority queue\n",
354 | "- because nodes are repeatedly added into the priority queue with different weight while exploring |E| edges, it'll raise the number of elements in the heap from $O(|V|)$ to $O(|E|)$\n",
355 | "- when the graph is sparse, its cost is $O(|V|+|E|)log(|E|)$ in the worst case\n",
356 | "- when the graph is dense, $|E|$ approaces $|V|^2$, so the cost can be as much as $O(|V|^2log|E|)$ in the worst case"
357 | ]
358 | },
359 | {
360 | "cell_type": "markdown",
361 | "metadata": {},
362 | "source": [
363 | "## Exercises\n",
364 | "1. Jurassic Jigsaw - https://open.kattis.com/problems/jurassicjigsaw\n",
365 | " - Hints: Complete Graph - use adjacency matrix where weight is # of DNA differences\n",
366 | " - Print total weight of a MST and it's edges\n",
367 | "- Minimum Spanning Tree problem: https://open.kattis.com/problems/minspantree\n",
368 | "- Island Hopping - https://open.kattis.com/problems/islandhopping\n",
369 | "- A Feast For Cats - https://open.kattis.com/problems/cats\n",
370 | "- Lost Map - https://open.kattis.com/problems/lostmap\n",
371 | " - Hints: complete graph; don't read redundant data; don't use ADT but directly use matrix\n",
372 | "- Nature Reserve - https://open.kattis.com/problems/naturereserve\n",
373 | "- Communication Satellite - https://open.kattis.com/problems/communicationssatellite\n",
374 | " - Hints: complete graph where weight is the gap (dist - (r1+r2) between each pair of antennas"
375 | ]
376 | },
377 | {
378 | "cell_type": "code",
379 | "execution_count": null,
380 | "metadata": {},
381 | "outputs": [],
382 | "source": []
383 | }
384 | ],
385 | "metadata": {
386 | "kernelspec": {
387 | "display_name": "C++14",
388 | "language": "C++14",
389 | "name": "xcpp14"
390 | },
391 | "language_info": {
392 | "codemirror_mode": "text/x-c++src",
393 | "file_extension": ".cpp",
394 | "mimetype": "text/x-c++src",
395 | "name": "c++",
396 | "version": "14"
397 | }
398 | },
399 | "nbformat": 4,
400 | "nbformat_minor": 2
401 | }
402 |
--------------------------------------------------------------------------------
/demo-programs/binaryTree/BST.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | using namespace std;
7 |
8 | // Binary Search Tree (BST) as Abstract Data Type (ADT)
9 | // Pointer-based implementation of BST
10 | #define DEBUG 1 // change it to 0 if you do not want debug statement to print
11 |
12 |
13 | // Binary Tree Node
14 | template
15 | struct Node {
16 | T data; //store data as key
17 | Node* lTree;
18 | Node* rTree;
19 | };
20 |
21 | template
22 | class BST {
23 | private:
24 | Node *root;
25 | int nodeCount; // keep track of no. of nodes in BST
26 |
27 | //inorder traversal
28 | void inorder(Node *p) const {
29 | if (p != nullptr) { // General case
30 | // 1. recursively call inorder on p's left subtree; traverse left tree
31 | // 2. visit node: print the data of root/current node
32 | // 3. recursively call inorder on p's right subtree; traverse right tree
33 | inorder(p->lTree);
34 | cout << p->data << " ";
35 | inorder(p->rTree);
36 | }
37 | // base case, do nothing; stop
38 | }
39 |
40 | //preorder traversal
41 | void preorder(Node *p) const {
42 | // Base case: if p equals nullptr, do nothing
43 | // General case: otherwise do the following:
44 | // 1. visit node
45 | // 2. traverse left tree
46 | // 3. traverse right tree
47 | // LEFT as an exercise
48 | cout << "FIXME: Implement preorder method..." << endl;
49 | }
50 |
51 | // postorder traversal
52 | void postorder(Node *p) const {
53 | // FIXME
54 | // LEFT as an exercise
55 | cout << "FIXME: Implement postorder method..." << endl;
56 | }
57 |
58 | // counts nodes in the longest path instead of edges
59 | // return 1 more than the actual definition of height according
60 | // to the opendsa text definition of height:
61 | // https://opendsa-server.cs.vt.edu/ODSA/Books/CS3/html/BinaryTree.html#definitions-and-properties
62 | int height(Node *p) const {
63 | if (p == nullptr)
64 | return 0;
65 | else
66 | return 1 + max(height(p->lTree), height(p->rTree));
67 | }
68 |
69 | int max(T x, T y) const {
70 | return (x >= y) ? x : y;
71 | }
72 |
73 | int leavesCount(Node *p) const {
74 | // FIXME - Left as an exercise
75 | cout << "FIXME: Implement leavesCount method..." << endl;
76 | // 1. Base case: if the tree is empty, return 0
77 | // 2. Base case: else if the left and right subtree are empty, return 1
78 | // 3. Otherwise, general case: return sum of leavesCount of left subtree and leavesCount of right subtree
79 | return 0;
80 | }
81 |
82 | // find and return the node with key value K, nullptr otherwise
83 | Node* find(Node *p, const T& K) const {
84 | if (p == nullptr) return nullptr;
85 | if (K == p->data)
86 | return p;
87 | else if (K < p->data)
88 | return find(p->lTree, K);
89 | else
90 | return find(p->rTree, K);
91 | }
92 |
93 | // insert a given node into the tree
94 | void insert(Node* &p, Node *newNode) {
95 | /*
96 | Given a binary search tree pointed to by p and a newNode,
97 | the function inserts the newNode in the correct place in the tree.
98 | Since the tree could be changed, it is passed by reference.
99 | */
100 | // 1. If the tree is empty, insert at that location
101 | // increment nodeCount
102 | if (p == nullptr) {
103 | p = newNode;
104 | this->nodeCount++;
105 | }
106 | else {
107 | // 2. Otherwise, recurse down the tree and insert at the correct branch
108 | // can handle the duplicates differently depending on the application
109 | if (newNode->data <= p->data)
110 | insert(p->lTree, newNode);
111 | // 2.c. Otherwise, recursively insert newNode into the right subtree
112 | else
113 | insert(p->rTree, newNode);
114 | }
115 | }
116 |
117 | Node* findMin(Node* p) {
118 | if (p->lTree == nullptr) return p;
119 | return findMin(p->lTree);
120 | }
121 |
122 | // remove a node from the tree
123 | // key: the key value of the record
124 | void remove(Node* &p, const T& key) {
125 | if (p != nullptr) // general case
126 | {
127 | if (p->data == key) {//found node
128 | if (p->lTree != nullptr && p->rTree != nullptr){//case 4: two children
129 | if (DEBUG)
130 | cout << "Debug: Deleting node with two children..." << endl;
131 | // find and copy the data of the min node on its right subtree to the node you're deleting
132 | Node* temp = findMin(p->rTree);
133 | p->data = temp->data;
134 | // remove the node with the duplicate value in the right subtree
135 | remove(p->rTree, temp->data);
136 | }
137 | else if (p->rTree != nullptr){//case 2: has right child
138 | if (DEBUG)
139 | cout << "Debug: Deleting node with right child..." << endl;
140 | Node* temp = p;
141 | // make the right child
142 | p = p->rTree;
143 | delete temp;
144 | }
145 | else if (p->lTree != nullptr){//case 2: has left child
146 | if (DEBUG)
147 | cout << "Debug: Deleting node with left child..." << endl;
148 | Node* temp = p;
149 | p = p->lTree;
150 | delete temp;
151 | }
152 | else{//case 1: no child/leaf node
153 | if (DEBUG)
154 | cout << "Debug: Deleting leaf node..." << endl;
155 | delete p;
156 | p = nullptr;
157 | }
158 | }
159 | else if (p->data > key) {//search left subtree
160 | if(DEBUG)
161 | cout << "Debug: Searching left subtree..." << endl;
162 | remove(p->lTree, key);
163 | }
164 | else {//search into right subtree
165 | if (DEBUG)
166 | cout << "Debug: Searching right subtree..." << endl;
167 | remove(p->rTree, key);
168 | }
169 | }
170 | }
171 |
172 | // Reinitialize tree
173 | void clear(Node* &p) {
174 | if (p != nullptr) {
175 | clear(p->lTree); // first clear the left subtree
176 | clear(p->rTree); // then clearn the right subtree
177 | delete p; // delete the node itself
178 | p = nullptr;
179 | }
180 | }
181 |
182 |
183 | public:
184 | //Default constructor
185 | BST() {
186 | this->root = nullptr;
187 | this->nodeCount = 0;
188 | }
189 |
190 | // check if the bst is empty
191 | bool isEmpty() const {
192 | return this->root == nullptr;
193 | }
194 |
195 | //enumerate BST using inorder traversal
196 | void inorder() const {
197 | inorder(this->root);
198 | }
199 |
200 | // enumerate BST using preorder traversal
201 | void preorder() const {
202 | preorder(this->root);
203 | }
204 |
205 | // enumerate BST using postorder traversal
206 | void postorder() const {
207 | postorder(this->root);
208 | }
209 |
210 | //find a node with the given key and return the node if found
211 | Node* find(const T& key) {
212 | return find(this->root, key);
213 | }
214 |
215 | // find an return height of BST
216 | int height() const {
217 | return height(this->root);
218 | }
219 |
220 | // find and return number of leaves in BST
221 | int leavesCount() const {
222 | return leavesCount(this->root);
223 | }
224 |
225 | // reset tree
226 | void clear() {
227 | clear(this->root);
228 | }
229 |
230 | // insert given item with key into the tree
231 | void insert(const T& key) {
232 | Node *node = new Node;
233 | node->data = key;
234 | node->lTree = nullptr;
235 | node->rTree = nullptr;
236 | insert(this->root, node);
237 | }
238 |
239 | // remove the node with the given key
240 | void remove(const T& key) {
241 | remove(this->root, key);
242 | }
243 |
244 | // get the value of the root node
245 | T getRoot(){
246 | return this->root->data;
247 | }
248 |
249 | //Destructor
250 | ~BST() {
251 | clear(this->root);
252 | }
253 | };
--------------------------------------------------------------------------------
/demo-programs/cbt/CBT.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include "CBT.h"
6 |
7 | using namespace std;
8 |
9 | int main() {
10 | // four levels: max # of nodes = 2^4-1 = 15
11 | CompleteBinaryTree cbt(20);
12 | cbt.updateRoot('A'); // level 0; add the root
13 | cbt.print();
14 | cout << "size = " << cbt.getSize() << endl;
15 | cout << "maxSize = " << cbt.getMaxSize() << endl;
16 |
17 | cbt.updateLeftChild(0, 'B'); // level 1
18 | cbt.updateRightChild(0, 'C');
19 | cbt.updateRightChild(1, 'D'); // level 2
20 | cbt.updateLeftChild(2, 'E');
21 | cbt.updateRightChild(2, 'F');
22 | cbt.updateLeftChild(5, 'G'); // level 3
23 | cbt.updateLeftChild(6, 'H');
24 | cbt.updateRightChild(6, 'I');
25 | cbt.print();
26 | cout << "size = " << cbt.getSize() << endl;
27 | // update left child that doesn't exist
28 | cbt.updateLeftChild(15, 'Z');
29 | return 0;
30 | }
--------------------------------------------------------------------------------
/demo-programs/cbt/CBT.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | using namespace std;
7 |
8 | // Complete Binary Tree - ADT
9 | // Array/Vector-based implementation
10 | class CompleteBinaryTree {
11 | // vector to store data for binary tree of char types
12 | private: vector bt;
13 | // meta data
14 | // root is the root index which is always as index 0 for non-empty tree
15 | private: int root, size, max_size;
16 |
17 | // does the actual inorder traversal
18 | private: void inorder(int root) {
19 | if (root >= this->bt.size() || this->bt[root] == '\0') // base case
20 | return;
21 | // inorder left-subtree
22 | inorder(2*root+1);
23 | // visit the node
24 | cout << this->bt[root] << " ";
25 | // inorder right-subtree
26 | inorder(2*root+2);
27 | }
28 |
29 | private:
30 | // converts tree to its mirror
31 | void mirror(int node) {
32 | if (this->bt[node] == '\0')
33 | return;
34 |
35 | int left = 2 * node + 1;
36 | int right = 2 * node + 2;
37 | mirror(left); // mirror left substree
38 | mirror(right); // mirror right subtree
39 | // swap the left/right nodes
40 | swap(this->bt[left], this->bt[right]);
41 | }
42 |
43 | // check if Tree is Full
44 | bool isFull() {
45 | return this->size == this->max_size;
46 | }
47 |
48 | // constructor
49 | public: CompleteBinaryTree(int max_size) {
50 | this->root = 0;
51 | this->size = 0;
52 | this->bt.resize(max_size);
53 | this->max_size = max_size;
54 | // initialize bt with \0 null character
55 | fill(this->bt.begin(), this->bt.end(), '\0');
56 | }
57 |
58 | public: // methods
59 | // get the actual size of Binary Tree
60 | int getSize() { return this->size; }
61 | // get the max size of Binary Tree
62 | int getMaxSize() { return this->max_size; }
63 |
64 | //updates or adds root node
65 | void updateRoot(char data) {
66 | if (bt[this->root] == '\0')
67 | this->size++;
68 | this->bt[this->root] = data;
69 | }
70 |
71 | // insert a node; left to right level by level
72 | void insertNode(char data) {
73 | if (isFull()) {
74 | cerr << "Debug: Binary Tree is Full!" << endl;
75 | return;
76 | }
77 | this->bt[size++] = data;
78 | }
79 |
80 | // insert or update left child of given parent with data
81 | void updateLeftChild(int parent, char data) {
82 | int leftChild = 2 * parent + 1;
83 | if (leftChild >= this->max_size)
84 | cerr << "Debug: Binary Tree out of bounds!" << endl;
85 | else if (this->bt[parent] == '\0')
86 | cerr << "Debug: parent at index " << parent << " does NOT exist!";
87 | else {
88 | if (bt[leftChild] == '\0')
89 | size++; // add a new child
90 | this->bt[leftChild] = data;
91 | }
92 | }
93 |
94 | // insert or update right child of given parent with data
95 | void updateRightChild(int parent, char data) {
96 | int rightChild = 2 * parent + 2;
97 | if (rightChild >= this->max_size)
98 | cerr << "Debug: Binary Tree out of bounds!" << endl;
99 | else if (this->bt[parent] == '\0')
100 | cerr << "Debug: Parent at index " << parent << " does NOT exist!";
101 | else {
102 | if (bt[rightChild] == '\0')
103 | size++;
104 | this->bt[rightChild] = data;
105 | }
106 | }
107 |
108 | // print all nodes level by level
109 | void print() const {
110 | for(auto ch: this->bt)
111 | if (ch == '\0') cout << "- ";
112 | else cout << ch << " ";
113 | cout << endl;
114 | }
115 |
116 | // public inorder method traversal
117 | void inorder() {
118 | this->inorder(0); // calls private inorder method
119 | }
120 |
121 | // FIXME: Write public preorder traversal method
122 | // FIXME: Write public postorder traversal method
123 |
124 | /* mirror tree:
125 | Changes the tree into its mirror image.
126 | So the tree...
127 | 4
128 | / \
129 | 2 5
130 | / \
131 | 1 3
132 | is changed to...
133 | 4
134 | / \
135 | 5 2
136 | / \
137 | 3 1
138 | Uses a recursive helper that recurs over the tree,
139 | swapping the left/right pointers.
140 | */
141 | void mirror() {
142 | this->mirror(this->root); // call private mirror
143 | }
144 | };
--------------------------------------------------------------------------------
/pdfs/00-Introduction.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/pdfs/00-Introduction.pdf
--------------------------------------------------------------------------------
/pdfs/AllPairsSP-Floyd.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/pdfs/AllPairsSP-Floyd.pdf
--------------------------------------------------------------------------------
/pdfs/BinaryTrees.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/pdfs/BinaryTrees.pdf
--------------------------------------------------------------------------------
/pdfs/DAG-TopologicalSort.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/pdfs/DAG-TopologicalSort.pdf
--------------------------------------------------------------------------------
/pdfs/GeneralTreesUnionFind.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/pdfs/GeneralTreesUnionFind.pdf
--------------------------------------------------------------------------------
/pdfs/GraphsImplementations.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/pdfs/GraphsImplementations.pdf
--------------------------------------------------------------------------------
/pdfs/GraphsIntro.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/pdfs/GraphsIntro.pdf
--------------------------------------------------------------------------------
/pdfs/GraphsShortestPaths.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/pdfs/GraphsShortestPaths.pdf
--------------------------------------------------------------------------------
/pdfs/Hashing.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/pdfs/Hashing.pdf
--------------------------------------------------------------------------------
/pdfs/Heaps-PriorityQueues.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/pdfs/Heaps-PriorityQueues.pdf
--------------------------------------------------------------------------------
/pdfs/MSTKruskals.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/pdfs/MSTKruskals.pdf
--------------------------------------------------------------------------------
/pdfs/Sorting.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/pdfs/Sorting.pdf
--------------------------------------------------------------------------------
/pdfs/SpanningTreesPrims.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/pdfs/SpanningTreesPrims.pdf
--------------------------------------------------------------------------------
/resources/BST-delete-Case1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/BST-delete-Case1.png
--------------------------------------------------------------------------------
/resources/BST-delete-Case3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/BST-delete-Case3.png
--------------------------------------------------------------------------------
/resources/BST-delete-case2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/BST-delete-case2.png
--------------------------------------------------------------------------------
/resources/BSTShape2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/BSTShape2.png
--------------------------------------------------------------------------------
/resources/BinarySearchTreeFiga.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/BinarySearchTreeFiga.png
--------------------------------------------------------------------------------
/resources/Bubble-sort-example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/Bubble-sort-example.gif
--------------------------------------------------------------------------------
/resources/DAG.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/DAG.png
--------------------------------------------------------------------------------
/resources/Dijkstra_Animation.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/Dijkstra_Animation.gif
--------------------------------------------------------------------------------
/resources/Dijkstras_progress_animation.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/Dijkstras_progress_animation.gif
--------------------------------------------------------------------------------
/resources/DirectedGraphImp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/DirectedGraphImp.png
--------------------------------------------------------------------------------
/resources/GeneralTrees.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/GeneralTrees.png
--------------------------------------------------------------------------------
/resources/Insertion-sort-example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/Insertion-sort-example.gif
--------------------------------------------------------------------------------
/resources/Kruskals.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/Kruskals.png
--------------------------------------------------------------------------------
/resources/MCST.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/MCST.png
--------------------------------------------------------------------------------
/resources/Merge-sort-example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/Merge-sort-example.gif
--------------------------------------------------------------------------------
/resources/Merge_sort_algorithm_diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/Merge_sort_algorithm_diagram.png
--------------------------------------------------------------------------------
/resources/OOPCM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/OOPCM.png
--------------------------------------------------------------------------------
/resources/OpenHashing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/OpenHashing.png
--------------------------------------------------------------------------------
/resources/ParentPtrTree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/ParentPtrTree.png
--------------------------------------------------------------------------------
/resources/UndirectedGraphImp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/UndirectedGraphImp.png
--------------------------------------------------------------------------------
/resources/binary-tree-cartoon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/binary-tree-cartoon.png
--------------------------------------------------------------------------------
/resources/binaryTree1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/binaryTree1.png
--------------------------------------------------------------------------------
/resources/binarytree.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/binarytree.gif
--------------------------------------------------------------------------------
/resources/clique.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/clique.png
--------------------------------------------------------------------------------
/resources/completeOrFull.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/completeOrFull.png
--------------------------------------------------------------------------------
/resources/connectedGraphs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/connectedGraphs.png
--------------------------------------------------------------------------------
/resources/denseGraph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/denseGraph.png
--------------------------------------------------------------------------------
/resources/directedGraphRepresentation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/directedGraphRepresentation.png
--------------------------------------------------------------------------------
/resources/full-binary-tree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/full-binary-tree.png
--------------------------------------------------------------------------------
/resources/fullAndCompleteBT.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/fullAndCompleteBT.png
--------------------------------------------------------------------------------
/resources/graph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/graph.png
--------------------------------------------------------------------------------
/resources/graphEx1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/graphEx1.png
--------------------------------------------------------------------------------
/resources/graphPathCycles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/graphPathCycles.png
--------------------------------------------------------------------------------
/resources/graphTypes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/graphTypes.png
--------------------------------------------------------------------------------
/resources/growthRates.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/growthRates.png
--------------------------------------------------------------------------------
/resources/growthRatesZoom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/growthRatesZoom.png
--------------------------------------------------------------------------------
/resources/growthrates.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/growthrates.gif
--------------------------------------------------------------------------------
/resources/k-path.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/k-path.png
--------------------------------------------------------------------------------
/resources/makeHeapAfter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/makeHeapAfter.png
--------------------------------------------------------------------------------
/resources/makeHeapAlgorithm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/makeHeapAlgorithm.png
--------------------------------------------------------------------------------
/resources/makeHeapBefore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/makeHeapBefore.png
--------------------------------------------------------------------------------
/resources/pushHeap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/pushHeap.png
--------------------------------------------------------------------------------
/resources/pushvsbuildheap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/pushvsbuildheap.png
--------------------------------------------------------------------------------
/resources/seqSearchBestWorstAvg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/seqSearchBestWorstAvg.png
--------------------------------------------------------------------------------
/resources/shellsortA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/shellsortA.png
--------------------------------------------------------------------------------
/resources/shellsortB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/shellsortB.png
--------------------------------------------------------------------------------
/resources/shellsortC.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/shellsortC.png
--------------------------------------------------------------------------------
/resources/sparseGraph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/sparseGraph.png
--------------------------------------------------------------------------------
/resources/sssp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/sssp.png
--------------------------------------------------------------------------------
/resources/topoSort.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/topoSort.png
--------------------------------------------------------------------------------
/resources/undirectedGraphRep.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/undirectedGraphRep.png
--------------------------------------------------------------------------------
/resources/weightedGraphRep.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rambasnet/IntroToAlgorithms/7df413644743fe84b81915c96fc1ae093172721a/resources/weightedGraphRep.png
--------------------------------------------------------------------------------