From aa1dda610b6e9458fce98663c800ed75e6bca32e Mon Sep 17 00:00:00 2001 From: zjl9959 Date: Wed, 26 Jul 2023 08:54:37 +0800 Subject: [PATCH] Add some notebooks using algviz to show the animation of basic algorithms running process. --- .gitpod.yml | 3 +- Algorithm/algviz/BubbleSort.ipynb | 99 +++++++ Algorithm/algviz/Dijkstra.ipynb | 332 +++++++++++++++++++++++ Algorithm/algviz/DisjointSet.ipynb | 238 ++++++++++++++++ Algorithm/algviz/Fibonacci.ipynb | 256 +++++++++++++++++ Algorithm/algviz/MergeSort.ipynb | 193 +++++++++++++ Algorithm/algviz/NQueens.ipynb | 124 +++++++++ Algorithm/algviz/Prim.ipynb | 201 ++++++++++++++ Algorithm/algviz/QuickSort.ipynb | 140 ++++++++++ Algorithm/algviz/ReverseLinkedList.ipynb | 98 +++++++ Algorithm/algviz/TrieTree.ipynb | 214 +++++++++++++++ requirements.txt | 3 +- 12 files changed, 1899 insertions(+), 2 deletions(-) create mode 100644 Algorithm/algviz/BubbleSort.ipynb create mode 100644 Algorithm/algviz/Dijkstra.ipynb create mode 100644 Algorithm/algviz/DisjointSet.ipynb create mode 100644 Algorithm/algviz/Fibonacci.ipynb create mode 100644 Algorithm/algviz/MergeSort.ipynb create mode 100644 Algorithm/algviz/NQueens.ipynb create mode 100644 Algorithm/algviz/Prim.ipynb create mode 100644 Algorithm/algviz/QuickSort.ipynb create mode 100644 Algorithm/algviz/ReverseLinkedList.ipynb create mode 100644 Algorithm/algviz/TrieTree.ipynb diff --git a/.gitpod.yml b/.gitpod.yml index 26a7d2a..5a6941a 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -2,7 +2,8 @@ image: file: .gitpod.Dockerfile tasks: - - init: pip install -r ./requirements.txt + - before: sudo apt-get install -y graphviz + init: pip install -r ./requirements.txt vscode: extensions: diff --git a/Algorithm/algviz/BubbleSort.ipynb b/Algorithm/algviz/BubbleSort.ipynb new file mode 100644 index 0000000..510a254 --- /dev/null +++ b/Algorithm/algviz/BubbleSort.ipynb @@ -0,0 +1,99 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Bubble sort algorithm\n", + "\n", + "## Description\n", + "\n", + "The [bubble sort algorithm](https://en.wikipedia.org/wiki/Bubble_sort) compares the size of two adjacent elements in turn during each round of scanning and if the two elements are in reverse order, the algorithm swaps the positions of the two elements. Suppose the algorithm scans from left to right, and each time it puts the larger of the two adjacent elements in the right. Then after this round of scanning, the maximum value in the scanned sequence will run to the far right of the scanned sequence. The bubble sort algorithm repeats the scanning process until all the elements are sorted.\n", + "\n", + "The bubble sort algorithm is also a comparison-based sorting algorithm and the sorting results are stable. The bubble sort algorithm needs $O(n^2)$ comparison operations regardless of the sequence of the input data. Therefore, in some cases, the algorithm is not as efficient as the insertion sort algorithm. And for large-scale cases, the bubble sort algorithm also dones’t have any advantage except for its simplicity.\n", + "\n", + "You can try to change the `input_nums` and see how this algorithm works on different input.\n", + "\n", + "## How to run?\n", + "\n", + "All the animations in this notebook are rendered by the [algviz](https://algviz.com/) algorithm animation engine in real time. You can follow this [guidance](https://algviz.com/en/installation.html) to set up your local environment or run this repo on Gitpod directly.\n", + "\n", + "*If you meet any problem, please report an πŸ‘‰[issue](https://github.com/zjl9959/algviz/issues)πŸ‘ˆ here.*\n", + "\n", + "## Reference\n", + "\n", + "https://algviz.com/en/BubbleSort/" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "Generated by algviz-0.3.0(see https://algviz.com).54-21-13012345" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import algviz\n", + "\n", + "def bubble_sort(data):\n", + " viz = algviz.Visualizer(0.5)\n", + " vector = viz.createVector(data, cell_size=(40, 160), histogram=True)\n", + " for i in range(len(vector)):\n", + " for j in range(len(vector)-i-1):\n", + " if vector[j] > vector[j+1]:\n", + " vector.mark(algviz.cRed, j)\n", + " vector.mark(algviz.cGreen, j+1)\n", + " viz.display()\n", + " vector.swap(j, j+1)\n", + " else:\n", + " vector.mark(algviz.cRed, j+1)\n", + " vector.mark(algviz.cGreen, j)\n", + " viz.display()\n", + " vector.mark(algviz.cGray, len(vector)-i-1, hold=True)\n", + " vector.removeMark(algviz.cGray)\n", + " viz.display()\n", + "\n", + "input_nums = [5, 4, -2, 1, -1, 3]\n", + "bubble_sort(input_nums)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + }, + "vscode": { + "interpreter": { + "hash": "ba530876bec2e6283b9bacba891681e9dff395534db17e3ec46729d6d41aa6cf" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Algorithm/algviz/Dijkstra.ipynb b/Algorithm/algviz/Dijkstra.ipynb new file mode 100644 index 0000000..a1b72c3 --- /dev/null +++ b/Algorithm/algviz/Dijkstra.ipynb @@ -0,0 +1,332 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Dijkstra\n", + "\n", + "## Optimal substructure\n", + "\n", + "**The shortest path between two nodes contains other shortest paths.**\n", + "\n", + "## Inputs\n", + "\n", + "+ The input graph should be **directed graph**.\n", + "+ All the edge weights should be **no negative**.\n", + "+ The source node id in the graph.\n", + "\n", + "## Auxiliary data structure\n", + "\n", + "+ `shortest_path_table:` stores the shortest path dist and the predecessor node in the shortest path from source node to all the nodes in graph.\n", + "\n", + "## Outputs\n", + "\n", + "+ The list of all the shortest path from the source node to the other nodes in the graph.\n", + "\n", + "## How to run?\n", + "\n", + "All the animations in this notebook are rendered by the [algviz](https://algviz.com/) algorithm animation engine in real time. You can follow this [guidance](https://algviz.com/en/installation.html) to set up your local environment or run this repo on Gitpod directly.\n", + "\n", + "*If you meet any problem, please report an πŸ‘‰[issue](https://github.com/zjl9959/algviz/issues)πŸ‘ˆ here.*" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import algviz\n", + "\n", + "class DjkstraSolver:\n", + " def __init__(self, nodes, edges, source):\n", + " self._nodes_num = len(nodes)\n", + " self._viz = algviz.Visualizer(4, 1, layout=True)\n", + " self._graph_nodes = algviz.parseGraph(nodes, edges)\n", + " self._graph = self._viz.createGraph(self._graph_nodes, 'Graph')\n", + " self._log = self._viz.createLogger(1, show_line_num=False)\n", + " self._log2 = self._viz.createLogger(3, show_line_num=False)\n", + " self._shortest_path_table = self._viz.createTable(3, self._nodes_num+1,\n", + " [[i-1 for i in range(self._nodes_num+1)], ['β™Ύ' for _ in range(self._nodes_num+1)],\n", + " [None for _ in range(self._nodes_num+1)]], 'shortest_path_table', show_index=False)\n", + " self._shortest_path_table[0][0] = 'node'\n", + " self._shortest_path_table[1][0] = 'dist'\n", + " self._shortest_path_table[2][0] = 'pred'\n", + " self._source_node = self._graph_nodes[source]\n", + " self._shortest_path_table[1][self._source_node.val+1] = 0\n", + " self._visited_nodes = set()\n", + "\n", + " def run(self):\n", + " self._viz.display()\n", + " while len(self._visited_nodes) < self._nodes_num:\n", + " node, dist = self.extract_min()\n", + " self._graph.markNode(algviz.color_tan, node, True)\n", + " self._shortest_path_table.mark(algviz.color_tan, 0, node.val+1, True)\n", + " self._log.write('Current shortest path: {} -> ... -> {}'.format(self._source_node.val, node.val))\n", + " self._viz.display(0.5)\n", + " for (neighbor, edge) in node.neighbors():\n", + " neighbor_dist = self._shortest_path_table[1][neighbor.val+1]\n", + " self._graph.markNode(algviz.color_green_yellow, neighbor, True)\n", + " self._shortest_path_table.mark(algviz.color_green_yellow, 0, neighbor.val+1, True)\n", + " if node != self._source_node:\n", + " self.mark_min_path(neighbor, algviz.color_aqua)\n", + " self._log2.write('{} -> ... -> {} current minimum distance: {}'.format(\n", + " self._source_node.val, neighbor.val, neighbor_dist))\n", + " self._viz.display()\n", + " self.mark_min_path(node, algviz.color_pink)\n", + " self._graph.markEdge(algviz.color_pink, node, neighbor)\n", + " self._log2.write('{} -> ... -> {} -> ... -> {} distance: {}'.format(\n", + " self._source_node.val, node.val, neighbor.val, dist + edge))\n", + " self._viz.display()\n", + " if neighbor_dist == 'β™Ύ' or dist + edge < neighbor_dist:\n", + " self._shortest_path_table[1][neighbor.val+1] = dist + edge\n", + " self._shortest_path_table[2][neighbor.val+1] = node.val\n", + " self._shortest_path_table.mark(algviz.color_pink, 1, neighbor.val+1)\n", + " self._shortest_path_table.mark(algviz.color_pink, 2, neighbor.val+1)\n", + " self._log2.write('Update the shortest path of node: {}'.format(neighbor.val))\n", + " self._viz.display(1)\n", + " self._graph.removeMark(algviz.color_green_yellow)\n", + " self._shortest_path_table.removeMark(algviz.color_green_yellow)\n", + " self._viz.display(1)\n", + " self._graph.removeMark(algviz.color_tan)\n", + " self._shortest_path_table.removeMark(algviz.color_tan)\n", + " self._viz.display(); self._viz.layout()\n", + "\n", + " def extract_min(self):\n", + " min_dist, min_index = None, None\n", + " for i in range(self._nodes_num):\n", + " dist = self._shortest_path_table[1][i+1]\n", + " if i not in self._visited_nodes and dist != 'β™Ύ' and (\n", + " min_dist == None or dist < min_dist):\n", + " min_dist = dist\n", + " min_index = i\n", + " self._visited_nodes.add(min_index)\n", + " return self._graph_nodes[min_index], min_dist\n", + "\n", + " def mark_min_path(self, node, color):\n", + " pred = self._shortest_path_table[2][node.val+1]\n", + " while pred != None and node != self._source_node:\n", + " pred_node = self._graph_nodes[pred]\n", + " self._graph.markNode(color, pred_node)\n", + " self._graph.markEdge(color, pred_node, node)\n", + " node = pred_node\n", + " pred = self._shortest_path_table[2][node.val+1]" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "513064228631131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213012486623513131213Current shortest path: 0 -> ... -> 0Current shortest path: 0 -> ... -> 0Current shortest path: 0 -> ... -> 0Current shortest path: 0 -> ... -> 0Current shortest path: 0 -> ... -> 0Current shortest path: 0 -> ... -> 0Current shortest path: 0 -> ... -> 0Current shortest path: 0 -> ... -> 1Current shortest path: 0 -> ... -> 1Current shortest path: 0 -> ... -> 1Current shortest path: 0 -> ... -> 1Current shortest path: 0 -> ... -> 1Current shortest path: 0 -> ... -> 1Current shortest path: 0 -> ... -> 1Current shortest path: 0 -> ... -> 1Current shortest path: 0 -> ... -> 1Current shortest path: 0 -> ... -> 5Current shortest path: 0 -> ... -> 5Current shortest path: 0 -> ... -> 5Current shortest path: 0 -> ... -> 5Current shortest path: 0 -> ... -> 5Current shortest path: 0 -> ... -> 5Current shortest path: 0 -> ... -> 5Current shortest path: 0 -> ... -> 5Current shortest path: 0 -> ... -> 5Current shortest path: 0 -> ... -> 5Current shortest path: 0 -> ... -> 5Current shortest path: 0 -> ... -> 5Current shortest path: 0 -> ... -> 5Current shortest path: 0 -> ... -> 2Current shortest path: 0 -> ... -> 2Current shortest path: 0 -> ... -> 2Current shortest path: 0 -> ... -> 2Current shortest path: 0 -> ... -> 6Current shortest path: 0 -> ... -> 6Current shortest path: 0 -> ... -> 6Current shortest path: 0 -> ... -> 6Current shortest path: 0 -> ... -> 6Current shortest path: 0 -> ... -> 3Current shortest path: 0 -> ... -> 3Current shortest path: 0 -> ... -> 3Current shortest path: 0 -> ... -> 3Current shortest path: 0 -> ... -> 4Current shortest path: 0 -> ... -> 4Update the shortest path of node: 1Update the shortest path of node: 1Update the shortest path of node: 1Update the shortest path of node: 6Update the shortest path of node: 1Update the shortest path of node: 6Update the shortest path of node: 1Update the shortest path of node: 6Update the shortest path of node: 4Update the shortest path of node: 1Update the shortest path of node: 6Update the shortest path of node: 4Update the shortest path of node: 1Update the shortest path of node: 6Update the shortest path of node: 4Update the shortest path of node: 6Update the shortest path of node: 40 -> ... -> 2 current minimum distance: β™ΎUpdate the shortest path of node: 40 -> ... -> 2 current minimum distance: β™Ύ0 -> ... -> 1 -> ... -> 2 distance: 50 -> ... -> 2 current minimum distance: β™Ύ0 -> ... -> 1 -> ... -> 2 distance: 5Update the shortest path of node: 20 -> ... -> 2 current minimum distance: β™Ύ0 -> ... -> 1 -> ... -> 2 distance: 5Update the shortest path of node: 20 -> ... -> 1 -> ... -> 2 distance: 5Update the shortest path of node: 20 -> ... -> 5 current minimum distance: β™ΎUpdate the shortest path of node: 20 -> ... -> 5 current minimum distance: β™Ύ0 -> ... -> 1 -> ... -> 5 distance: 30 -> ... -> 5 current minimum distance: β™Ύ0 -> ... -> 1 -> ... -> 5 distance: 3Update the shortest path of node: 50 -> ... -> 5 current minimum distance: β™Ύ0 -> ... -> 1 -> ... -> 5 distance: 3Update the shortest path of node: 50 -> ... -> 5 current minimum distance: β™Ύ0 -> ... -> 1 -> ... -> 5 distance: 3Update the shortest path of node: 50 -> ... -> 1 -> ... -> 5 distance: 3Update the shortest path of node: 50 -> ... -> 3 current minimum distance: β™ΎUpdate the shortest path of node: 50 -> ... -> 3 current minimum distance: β™Ύ0 -> ... -> 5 -> ... -> 3 distance: 50 -> ... -> 3 current minimum distance: β™Ύ0 -> ... -> 5 -> ... -> 3 distance: 5Update the shortest path of node: 30 -> ... -> 3 current minimum distance: β™Ύ0 -> ... -> 5 -> ... -> 3 distance: 5Update the shortest path of node: 30 -> ... -> 5 -> ... -> 3 distance: 5Update the shortest path of node: 30 -> ... -> 6 current minimum distance: 6Update the shortest path of node: 30 -> ... -> 6 current minimum distance: 60 -> ... -> 5 -> ... -> 6 distance: 40 -> ... -> 6 current minimum distance: 60 -> ... -> 5 -> ... -> 6 distance: 4Update the shortest path of node: 60 -> ... -> 6 current minimum distance: 60 -> ... -> 5 -> ... -> 6 distance: 4Update the shortest path of node: 60 -> ... -> 5 -> ... -> 6 distance: 4Update the shortest path of node: 60 -> ... -> 2 current minimum distance: 5Update the shortest path of node: 60 -> ... -> 2 current minimum distance: 50 -> ... -> 5 -> ... -> 2 distance: 40 -> ... -> 2 current minimum distance: 50 -> ... -> 5 -> ... -> 2 distance: 4Update the shortest path of node: 20 -> ... -> 2 current minimum distance: 50 -> ... -> 5 -> ... -> 2 distance: 4Update the shortest path of node: 20 -> ... -> 2 current minimum distance: 50 -> ... -> 5 -> ... -> 2 distance: 4Update the shortest path of node: 20 -> ... -> 5 -> ... -> 2 distance: 4Update the shortest path of node: 20 -> ... -> 3 current minimum distance: 5Update the shortest path of node: 20 -> ... -> 3 current minimum distance: 50 -> ... -> 2 -> ... -> 3 distance: 5Update the shortest path of node: 20 -> ... -> 3 current minimum distance: 50 -> ... -> 2 -> ... -> 3 distance: 5Update the shortest path of node: 20 -> ... -> 3 current minimum distance: 50 -> ... -> 2 -> ... -> 3 distance: 50 -> ... -> 3 current minimum distance: 50 -> ... -> 2 -> ... -> 3 distance: 50 -> ... -> 4 current minimum distance: 80 -> ... -> 2 -> ... -> 3 distance: 50 -> ... -> 4 current minimum distance: 80 -> ... -> 6 -> ... -> 4 distance: 70 -> ... -> 4 current minimum distance: 80 -> ... -> 6 -> ... -> 4 distance: 7Update the shortest path of node: 40 -> ... -> 4 current minimum distance: 80 -> ... -> 6 -> ... -> 4 distance: 7Update the shortest path of node: 40 -> ... -> 4 current minimum distance: 80 -> ... -> 6 -> ... -> 4 distance: 7Update the shortest path of node: 40 -> ... -> 6 -> ... -> 4 distance: 7Update the shortest path of node: 40 -> ... -> 4 current minimum distance: 7Update the shortest path of node: 40 -> ... -> 4 current minimum distance: 70 -> ... -> 3 -> ... -> 4 distance: 8Update the shortest path of node: 40 -> ... -> 4 current minimum distance: 70 -> ... -> 3 -> ... -> 4 distance: 8Update the shortest path of node: 40 -> ... -> 4 current minimum distance: 70 -> ... -> 3 -> ... -> 4 distance: 8Update the shortest path of node: 40 -> ... -> 4 current minimum distance: 70 -> ... -> 3 -> ... -> 4 distance: 8-1node0123456β™Ύdistβ™Ύ0β™Ύβ™Ύβ™Ύβ™Ύβ™Ύβ™Ύprednode0123456dist0β™Ύβ™Ύβ™Ύβ™Ύβ™Ύβ™Ύprednode0123456dist0β™Ύ2β™Ύβ™Ύβ™Ύβ™Ύβ™Ύpred0node0123456dist02β™Ύβ™Ύβ™Ύβ™Ύβ™Ύpred0node0123456dist02β™Ύβ™Ύβ™Ύβ™Ύβ™Ύ6pred00node0123456dist02β™Ύβ™Ύβ™Ύβ™Ύ6pred00node0123456dist02β™Ύβ™Ύβ™Ύ8β™Ύ6pred000node0123456dist02β™Ύβ™Ύ8β™Ύ6pred000node0123456dist02β™Ύβ™Ύ8β™Ύ6pred000node0123456dist02β™Ύβ™Ύ8β™Ύ6pred000node0123456dist02β™Ύβ™Ύ8β™Ύ6pred000node0123456dist02β™Ύ5β™Ύ8β™Ύ6pred0100node0123456dist025β™Ύ8β™Ύ6pred0100node0123456dist025β™Ύ8β™Ύ6pred0100node0123456dist025β™Ύ8β™Ύ6pred0100node0123456dist025β™Ύ8β™Ύ36pred01010node0123456dist025β™Ύ836pred01010node0123456dist025β™Ύ836pred01010node0123456dist025β™Ύ836pred01010node0123456dist025β™Ύ836pred01010node0123456dist025β™Ύ5836pred015010node0123456dist0255836pred015010node0123456dist0255836pred015010node0123456dist0255836pred015010node0123456dist02558364pred0150105node0123456dist0255834pred015015node0123456dist0255834pred015015node0123456dist0255834pred015015node0123456dist02545834pred0155015node0123456dist0245834pred055015node0123456dist0245834pred055015node0123456dist0245834pred055015node0123456dist0245834pred055015node0123456dist0245834pred055015node0123456dist0245834pred055015node0123456dist0245834pred055015node0123456dist0245834pred055015node0123456dist02458734pred0550615node0123456dist0245734pred055615node0123456dist0245734pred055615node0123456dist0245734pred055615node0123456dist0245734pred055615node0123456dist0245734pred055615node0123456dist0245734pred055615node0123456dist0245734pred055615 Make your Python code alive A L Z G V I Graph:shortest_path_table:" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "image/svg+xml": { + "duration": 143.5, + "frames": 45, + "layout": { + "9": [ + 5, + 5, + 444, + 193 + ], + "10": [ + 454, + 157, + 275, + 16 + ], + "11": [ + 454, + 178, + 312, + 47 + ], + "12": [ + 454, + 5, + 329, + 147 + ] + }, + "size": [ + 788, + 230 + ] + } + }, + "output_type": "display_data" + } + ], + "source": [ + "# Test case1.\n", + "nodes = [0, 1, 2, 3, 4, 5, 6]\n", + "edges = [(0, 1, 2), (0, 6, 6), (0, 4, 8),\n", + " (1, 2, 3), (1, 5, 1),\n", + " (2, 3, 1),\n", + " (3, 4, 3),\n", + " (5, 3, 2), (5, 6, 1), (5, 2, 1),\n", + " (6, 4, 3)]\n", + "DjkstraSolver(nodes, edges, 0).run()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "2014362231131016223231413101622323141310162232314131016223231413101622323141310162232314131016223231413101622323141310162232314131016223231413101622323141310162232314131016223231413101622323141310162232314131016223231413101622323141310162232314131016223231413101622323141310162232314131016223231413101622323141310162232314131016223231413101622323141310162232314131016223231413101622323141310162232314131Current shortest path: 4 -> ... -> 4Current shortest path: 4 -> ... -> 4Current shortest path: 4 -> ... -> 4Current shortest path: 4 -> ... -> 4Current shortest path: 4 -> ... -> 4Current shortest path: 4 -> ... -> 1Current shortest path: 4 -> ... -> 0Current shortest path: 4 -> ... -> 0Current shortest path: 4 -> ... -> 0Current shortest path: 4 -> ... -> 0Current shortest path: 4 -> ... -> 0Current shortest path: 4 -> ... -> 0Current shortest path: 4 -> ... -> 0Current shortest path: 4 -> ... -> 0Current shortest path: 4 -> ... -> 0Current shortest path: 4 -> ... -> 0Current shortest path: 4 -> ... -> 0Current shortest path: 4 -> ... -> 0Current shortest path: 4 -> ... -> 2Current shortest path: 4 -> ... -> 2Current shortest path: 4 -> ... -> 2Current shortest path: 4 -> ... -> 2Current shortest path: 4 -> ... -> 2Current shortest path: 4 -> ... -> 2Current shortest path: 4 -> ... -> 2Current shortest path: 4 -> ... -> 3Current shortest path: 4 -> ... -> 3Current shortest path: 4 -> ... -> 3Current shortest path: 4 -> ... -> 3Current shortest path: 4 -> ... -> 3Update the shortest path of node: 0Update the shortest path of node: 0Update the shortest path of node: 0Update the shortest path of node: 1Update the shortest path of node: 0Update the shortest path of node: 1Update the shortest path of node: 0Update the shortest path of node: 1Update the shortest path of node: 0Update the shortest path of node: 1Update the shortest path of node: 0Update the shortest path of node: 14 -> ... -> 1 current minimum distance: 1Update the shortest path of node: 14 -> ... -> 1 current minimum distance: 14 -> ... -> 0 -> ... -> 1 distance: 9Update the shortest path of node: 14 -> ... -> 1 current minimum distance: 14 -> ... -> 0 -> ... -> 1 distance: 94 -> ... -> 1 current minimum distance: 14 -> ... -> 0 -> ... -> 1 distance: 94 -> ... -> 2 current minimum distance: β™Ύ4 -> ... -> 0 -> ... -> 1 distance: 94 -> ... -> 2 current minimum distance: β™Ύ4 -> ... -> 0 -> ... -> 2 distance: 54 -> ... -> 2 current minimum distance: β™Ύ4 -> ... -> 0 -> ... -> 2 distance: 5Update the shortest path of node: 24 -> ... -> 2 current minimum distance: β™Ύ4 -> ... -> 0 -> ... -> 2 distance: 5Update the shortest path of node: 24 -> ... -> 0 -> ... -> 2 distance: 5Update the shortest path of node: 24 -> ... -> 3 current minimum distance: β™ΎUpdate the shortest path of node: 24 -> ... -> 3 current minimum distance: β™Ύ4 -> ... -> 0 -> ... -> 3 distance: 54 -> ... -> 3 current minimum distance: β™Ύ4 -> ... -> 0 -> ... -> 3 distance: 5Update the shortest path of node: 34 -> ... -> 3 current minimum distance: β™Ύ4 -> ... -> 0 -> ... -> 3 distance: 5Update the shortest path of node: 34 -> ... -> 3 current minimum distance: β™Ύ4 -> ... -> 0 -> ... -> 3 distance: 5Update the shortest path of node: 34 -> ... -> 0 -> ... -> 3 distance: 5Update the shortest path of node: 34 -> ... -> 1 current minimum distance: 1Update the shortest path of node: 34 -> ... -> 1 current minimum distance: 14 -> ... -> 2 -> ... -> 1 distance: 8Update the shortest path of node: 34 -> ... -> 1 current minimum distance: 14 -> ... -> 2 -> ... -> 1 distance: 84 -> ... -> 1 current minimum distance: 14 -> ... -> 2 -> ... -> 1 distance: 84 -> ... -> 3 current minimum distance: 54 -> ... -> 2 -> ... -> 1 distance: 84 -> ... -> 3 current minimum distance: 54 -> ... -> 2 -> ... -> 3 distance: 64 -> ... -> 2 -> ... -> 1 distance: 84 -> ... -> 3 current minimum distance: 54 -> ... -> 2 -> ... -> 3 distance: 64 -> ... -> 2 -> ... -> 1 distance: 84 -> ... -> 3 current minimum distance: 54 -> ... -> 2 -> ... -> 3 distance: 64 -> ... -> 3 current minimum distance: 54 -> ... -> 2 -> ... -> 3 distance: 64 -> ... -> 4 current minimum distance: 04 -> ... -> 2 -> ... -> 3 distance: 64 -> ... -> 4 current minimum distance: 04 -> ... -> 3 -> ... -> 4 distance: 64 -> ... -> 2 -> ... -> 3 distance: 64 -> ... -> 4 current minimum distance: 04 -> ... -> 3 -> ... -> 4 distance: 64 -> ... -> 2 -> ... -> 3 distance: 64 -> ... -> 4 current minimum distance: 04 -> ... -> 3 -> ... -> 4 distance: 6-1node01234β™Ύdistβ™Ύβ™Ύβ™Ύβ™Ύβ™Ύ0prednode01234distβ™Ύβ™Ύβ™Ύβ™Ύ0prednode01234distβ™Ύ3β™Ύβ™Ύβ™Ύ0pred4node01234dist3β™Ύβ™Ύβ™Ύ0pred4node01234dist3β™Ύ1β™Ύβ™Ύ0pred44node01234dist31β™Ύβ™Ύ0pred44node01234dist31β™Ύβ™Ύ0pred44node01234dist31β™Ύβ™Ύ0pred44node01234dist31β™Ύβ™Ύ0pred44node01234dist31β™Ύβ™Ύ0pred44node01234dist31β™Ύβ™Ύ0pred44node01234dist31β™Ύβ™Ύ0pred44node01234dist31β™Ύβ™Ύ0pred44node01234dist31β™Ύ5β™Ύ0pred440node01234dist315β™Ύ0pred440node01234dist315β™Ύ0pred440node01234dist315β™Ύ0pred440node01234dist315β™Ύ50pred4400node01234dist31550pred4400node01234dist31550pred4400node01234dist31550pred4400node01234dist31550pred4400node01234dist31550pred4400node01234dist31550pred4400node01234dist31550pred4400node01234dist31550pred4400node01234dist31550pred4400node01234dist31550pred4400node01234dist31550pred4400node01234dist31550pred4400node01234dist31550pred4400 Make your Python code alive A L Z G V I Graph:shortest_path_table:" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "image/svg+xml": { + "duration": 104.5, + "frames": 31, + "layout": { + "14": [ + 5, + 5, + 364, + 169 + ], + "15": [ + 374, + 157, + 275, + 16 + ], + "16": [ + 374, + 178, + 312, + 47 + ], + "17": [ + 374, + 5, + 249, + 147 + ] + }, + "size": [ + 691, + 230 + ] + } + }, + "output_type": "display_data" + } + ], + "source": [ + "# Test case2, graph with cycle.\n", + "nodes = [0, 1, 2, 3, 4]\n", + "edges = [(0, 1, 6), (0, 2, 2), (0, 3, 2),\n", + " (2, 1, 3), (2, 3, 1),\n", + " (3, 4, 1),\n", + " (4, 0, 3), (4, 1, 1)]\n", + "DjkstraSolver(nodes, edges, 4).run()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "02111-301121-301121-301121-301121-301121-301121-301121-301121-301121-301121-301121-301121-301121-301121-3Current shortest path: 0 -> ... -> 0Current shortest path: 0 -> ... -> 0Current shortest path: 0 -> ... -> 0Current shortest path: 0 -> ... -> 1Current shortest path: 0 -> ... -> 1Current shortest path: 0 -> ... -> 1Current shortest path: 0 -> ... -> 1Current shortest path: 0 -> ... -> 1Current shortest path: 0 -> ... -> 2Current shortest path: 0 -> ... -> 2Current shortest path: 0 -> ... -> 2Current shortest path: 0 -> ... -> 2Current shortest path: 0 -> ... -> 2Current shortest path: 0 -> ... -> 2Update the shortest path of node: 1Update the shortest path of node: 1Update the shortest path of node: 1Update the shortest path of node: 10 -> ... -> 2 current minimum distance: β™ΎUpdate the shortest path of node: 10 -> ... -> 2 current minimum distance: β™Ύ0 -> ... -> 1 -> ... -> 2 distance: 20 -> ... -> 2 current minimum distance: β™Ύ0 -> ... -> 1 -> ... -> 2 distance: 2Update the shortest path of node: 20 -> ... -> 2 current minimum distance: β™Ύ0 -> ... -> 1 -> ... -> 2 distance: 2Update the shortest path of node: 20 -> ... -> 2 current minimum distance: β™Ύ0 -> ... -> 1 -> ... -> 2 distance: 2Update the shortest path of node: 20 -> ... -> 1 -> ... -> 2 distance: 2Update the shortest path of node: 20 -> ... -> 0 current minimum distance: 0Update the shortest path of node: 20 -> ... -> 0 current minimum distance: 00 -> ... -> 2 -> ... -> 0 distance: -10 -> ... -> 0 current minimum distance: 00 -> ... -> 2 -> ... -> 0 distance: -1Update the shortest path of node: 00 -> ... -> 0 current minimum distance: 00 -> ... -> 2 -> ... -> 0 distance: -1Update the shortest path of node: 00 -> ... -> 0 current minimum distance: 00 -> ... -> 2 -> ... -> 0 distance: -1Update the shortest path of node: 0-1node012β™Ύdistβ™Ύ0β™Ύβ™Ύprednode012dist0β™Ύβ™Ύprednode012dist0β™Ύ1β™Ύpred0node012dist01β™Ύpred0node012dist01β™Ύpred0node012dist01β™Ύpred0node012dist01β™Ύpred0node012dist01β™Ύ2pred01node012dist012pred01node012dist012pred01node012dist012pred01node012dist012pred01node012dist0-112pred201node012dist-112pred201node012dist-112pred201 Make your Python code alive A L Z G V I Graph:shortest_path_table:" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "image/svg+xml": { + "duration": 49.5, + "frames": 15, + "layout": { + "19": [ + 393, + 56, + 204, + 95 + ], + "20": [ + 322, + 5, + 275, + 16 + ], + "21": [ + 5, + 5, + 312, + 47 + ], + "22": [ + 602, + 5, + 169, + 145.5 + ] + }, + "size": [ + 776, + 174 + ] + } + }, + "output_type": "display_data" + } + ], + "source": [ + "# Test case3, failed when there exist a cycle with negative edge value.\n", + "nodes = [0, 1, 2]\n", + "edges = [(0, 1, 1), (1, 2, 1), (2, 0, -3)]\n", + "DjkstraSolver(nodes, edges, 0).run()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + }, + "vscode": { + "interpreter": { + "hash": "ba530876bec2e6283b9bacba891681e9dff395534db17e3ec46729d6d41aa6cf" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Algorithm/algviz/DisjointSet.ipynb b/Algorithm/algviz/DisjointSet.ipynb new file mode 100644 index 0000000..cec6186 --- /dev/null +++ b/Algorithm/algviz/DisjointSet.ipynb @@ -0,0 +1,238 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Disjoint-set\n", + "\n", + "Disjoint-set(also called union-find set) is a special data structure for checking if two elements belong to the same set and merging two sets into one.\n", + "\n", + "## Disjoint-set forest\n", + "\n", + "If we put each element into one set, then we get a disjoint-set forest, this is the initial state.\n", + "\n", + "Each element maintains a reference that pointer to its parent element. If the pointer is null, then this element is the root of the set it belongs to. Initially, all the potiners are null.\n", + "\n", + "## Find\n", + "\n", + "At this step, we find the root element of a given element. The root element stands for the set of the given element belongs to.\n", + "\n", + "## Union\n", + "\n", + "Merge two sets into one set. Usually, we give two elements which belongs to two sets, then the algorithm merge one set into another set.\n", + "\n", + "## Optimize\n", + "\n", + "If the set tree is unbalanced, the find operation will cost a lot of time. So, we can do the path compression during the find operation. That is, we set all the references of all the elements in the query path to the root element of the set.\n", + "\n", + "## How to run?\n", + "\n", + "All the animations in this notebook are rendered by the [algviz](https://algviz.com/) algorithm animation engine in real time. You can follow this [guidance](https://algviz.com/en/installation.html) to set up your local environment or run this repo on Gitpod directly.\n", + "\n", + "*If you meet any problem, please report an πŸ‘‰[issue](https://github.com/zjl9959/algviz/issues)πŸ‘ˆ here.*" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import algviz\n", + "\n", + "class DisjointSet:\n", + " def __init__(self, nums):\n", + " self.viz = algviz.Visualizer(1, layout=True)\n", + " self.sets = self.viz.createGraph()\n", + " self.log1 = self.viz.createLogger(1, None, 16, False)\n", + " self.log2 = self.viz.createLogger(1, None, 16, False)\n", + " self.num2elem = dict()\n", + " for x in nums:\n", + " elem = algviz.TreeNode(x)\n", + " self.num2elem[x] = elem\n", + " self.sets.addNode(elem)\n", + " elem.parent = None\n", + " self.viz.display()\n", + "\n", + " def find(self, x):\n", + " elem = self.num2elem[x]\n", + " self.sets.markNode(algviz.cLime, elem)\n", + " self.viz.display(0.5)\n", + " if elem.parent == None:\n", + " self.sets.markNode(algviz.cTomato, elem, True)\n", + " self.viz.display(0.5)\n", + " return elem.val\n", + " else:\n", + " res = self.find(elem.parent.val)\n", + " new_parent = self.num2elem[res]\n", + " if elem.parent != new_parent:\n", + " self.log2.write('Compress path: {} -> {}'.format(elem.val, new_parent.val))\n", + " elem.parent.remove(elem)\n", + " elem.parent = new_parent\n", + " elem.parent.add(elem)\n", + " self.viz.display()\n", + " self.log2.write('')\n", + " return res\n", + "\n", + " def union(self, x, y):\n", + " self.log1.write('Union: {} <=> {}'.format(x, y))\n", + " root1 = self.num2elem[self.find(x)]\n", + " root2 = self.num2elem[self.find(y)]\n", + " self.sets.removeMark(algviz.cTomato)\n", + " if root1 != root2:\n", + " root1.parent = root2\n", + " root2.add(root1)\n", + " self.viz.display()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can try to change the numbers in the `elements` and the union operations in the `union_list` to see what will happen." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "31402012340123401234012340123401234012340123401234012340123401234012340123401234013240132401324013240132401324013240132401324Union: 0 <=> 1Union: 0 <=> 1Union: 0 <=> 1Union: 0 <=> 1Union: 0 <=> 1Union: 2 <=> 3Union: 2 <=> 3Union: 2 <=> 3Union: 2 <=> 3Union: 2 <=> 3Union: 3 <=> 1Union: 3 <=> 1Union: 3 <=> 1Union: 3 <=> 1Union: 3 <=> 1Union: 4 <=> 2Union: 4 <=> 2Union: 4 <=> 2Union: 4 <=> 2Union: 4 <=> 2Union: 4 <=> 2Union: 4 <=> 2Union: 4 <=> 2Union: 4 <=> 2Compress path: 2 -> 1 Make your Python code alive A L Z G V I " + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "image/svg+xml": { + "duration": 31.5, + "frames": 25, + "layout": { + "0": [ + 5, + 57, + 260, + 188 + ], + "1": [ + 5, + 31, + 145, + 21 + ], + "2": [ + 5, + 5, + 215, + 21 + ] + }, + "size": [ + 270, + 250 + ] + } + }, + "output_type": "display_data" + } + ], + "source": [ + "elements = [0, 1, 2, 3, 4]\n", + "union_list = [(0, 1), (2, 3), (3, 1), (4, 2)]\n", + "diset = DisjointSet(elements)\n", + "for (x, y) in union_list:\n", + " diset.union(x, y)\n", + "diset.viz.layout(300)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "416728593001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345879601234587960123458796012345879601234587960123458796012345879601234587960123458796Union: 0 <=> 1Union: 0 <=> 1Union: 0 <=> 1Union: 0 <=> 1Union: 0 <=> 1Union: 2 <=> 3Union: 2 <=> 3Union: 2 <=> 3Union: 2 <=> 3Union: 2 <=> 3Union: 4 <=> 3Union: 4 <=> 3Union: 4 <=> 3Union: 4 <=> 3Union: 4 <=> 3Union: 0 <=> 4Union: 0 <=> 4Union: 0 <=> 4Union: 0 <=> 4Union: 0 <=> 4Union: 0 <=> 4Union: 0 <=> 4Union: 0 <=> 4Union: 0 <=> 4Union: 7 <=> 8Union: 7 <=> 8Union: 7 <=> 8Union: 7 <=> 8Union: 7 <=> 8Union: 9 <=> 8Union: 9 <=> 8Union: 9 <=> 8Union: 9 <=> 8Union: 9 <=> 8Union: 9 <=> 5Union: 9 <=> 5Union: 9 <=> 5Union: 9 <=> 5Union: 9 <=> 5Union: 9 <=> 5Union: 9 <=> 5Union: 7 <=> 6Union: 7 <=> 6Union: 7 <=> 6Union: 7 <=> 6Union: 7 <=> 6Union: 7 <=> 6Union: 7 <=> 6Union: 7 <=> 6Union: 7 <=> 6Compress path: 7 -> 5 Make your Python code alive A L Z G V I " + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "image/svg+xml": { + "duration": 61, + "frames": 51, + "layout": { + "4": [ + 5, + 31, + 530, + 260 + ], + "5": [ + 225, + 5, + 145, + 21 + ], + "6": [ + 5, + 5, + 215, + 21 + ] + }, + "size": [ + 540, + 296 + ] + } + }, + "output_type": "display_data" + } + ], + "source": [ + "elements = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n", + "union_list = [\n", + " (0, 1), (2, 3), (4, 3), (0, 4), # Set0: (0, 1, 2, 3, 4)\n", + " (7, 8), (9, 8), (9, 5), (7, 6) # Set1: (5, 6, 7, 8, 9)\n", + "]\n", + "diset = DisjointSet(elements)\n", + "for (x, y) in union_list:\n", + " diset.union(x, y)\n", + "diset.viz.layout(600)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + }, + "vscode": { + "interpreter": { + "hash": "ba530876bec2e6283b9bacba891681e9dff395534db17e3ec46729d6d41aa6cf" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Algorithm/algviz/Fibonacci.ipynb b/Algorithm/algviz/Fibonacci.ipynb new file mode 100644 index 0000000..ee16b80 --- /dev/null +++ b/Algorithm/algviz/Fibonacci.ipynb @@ -0,0 +1,256 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# What is a fibonacci number?\n", + "\n", + "The Fibonacci numbers may be defined by the recurrence relation:\n", + "\n", + "$F_{0}=0$, $F_{1}=1$ and $F_{n}=F_{n-1}+F_{n-2}$\n", + "\n", + "This is the first ten numbers in fibonacci sequence:\n", + "\n", + "> 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ...\n", + "\n", + "Reference: https://en.wikipedia.org/wiki/Fibonacci_number\n", + "\n", + "## How to run?\n", + "\n", + "All the animations in this notebook are rendered by the [algviz](https://algviz.com/) algorithm animation engine in real time. You can follow this [guidance](https://algviz.com/en/installation.html) to set up your local environment or run this repo on Gitpod directly.\n", + "\n", + "*If you meet any problem, please report an πŸ‘‰[issue](https://github.com/zjl9959/algviz/issues)πŸ‘ˆ here.*" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Solution\n", + "\n", + "The code is simple and intuitive.\n", + "\n", + "We just need to implement the recurrence relation as below:\n", + "\n", + "```python\n", + "def fib(n):\n", + " if n <= 1:\n", + " return n\n", + " return fib(n-1) + fib(n-2)\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Visualization\n", + "\n", + "We use the [RecursiveTree](https://algviz.com/en/RecursiveTree/) in algviz to show the recursive animation of this algorithm." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import algviz\n", + "\n", + "class FibViz:\n", + " def __init__(self) -> None:\n", + " self.viz = algviz.Visualizer(1)\n", + " name = \"Fibonacci Recursive Tree\"\n", + " self.tree = algviz.RecursiveTree(self.viz, name)\n", + "\n", + " def fib(self, n):\n", + " self.tree.forward('fib({})'.format(n)); self.viz.display()\n", + " if n <= 1:\n", + " self.tree.backward(n); self.viz.display()\n", + " return n\n", + " res = self.fib(n-1) + self.fib(n-2)\n", + " self.tree.backward(res); self.viz.display()\n", + " return res" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Fibonacci Recursive Tree:" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "fib(2)110Generated by algviz-0.3.0(see https://algviz.com)." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Fib(2)= 1\n" + ] + } + ], + "source": [ + "print('Fib(2)=', FibViz().fib(2))" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Fibonacci Recursive Tree:" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "fib(3)21110Generated by algviz-0.3.0(see https://algviz.com)." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Fib(3)= 2\n" + ] + } + ], + "source": [ + "print('Fib(3)=', FibViz().fib(3))" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Fibonacci Recursive Tree:" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "fib(4)321111010Generated by algviz-0.3.0(see https://algviz.com)." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Fib(4)= 3\n" + ] + } + ], + "source": [ + "print('Fib(4)=', FibViz().fib(4))" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Fibonacci Recursive Tree:" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "fib(5)532211110101110Generated by algviz-0.3.0(see https://algviz.com)." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Fib(5)= 5\n" + ] + } + ], + "source": [ + "print('Fib(5)=', FibViz().fib(5))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + }, + "vscode": { + "interpreter": { + "hash": "ba530876bec2e6283b9bacba891681e9dff395534db17e3ec46729d6d41aa6cf" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Algorithm/algviz/MergeSort.ipynb b/Algorithm/algviz/MergeSort.ipynb new file mode 100644 index 0000000..c0ae0c3 --- /dev/null +++ b/Algorithm/algviz/MergeSort.ipynb @@ -0,0 +1,193 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Merge sort algorithm\n", + "\n", + "## Introduction\n", + "\n", + "The merge sort algorithm uses the idea of divide and conquer, which reduces the big things to small ones and solves the small thing recursively, then gather the solutions together! The idea of divide and conquer includes the divide, resolve, and merge processes.\n", + "\n", + "1. Divide: divide the sequence to be sorted into two subsequences (usually from the middle).\n", + "2. Resolve: call the resolve function recursively on subsequences until the subsequence can be sorted directly.\n", + "3. Merge: merge the sorted subsequences to get the sorting solution of the parent sequence.\n", + "\n", + "## How to run?\n", + "\n", + "All the animations in this notebook are rendered by the [algviz](https://algviz.com/) algorithm animation engine in real time. You can follow this [guidance](https://algviz.com/en/installation.html) to set up your local environment or run this repo on Gitpod directly.\n", + "\n", + "*If you meet any problem, please report an πŸ‘‰[issue](https://github.com/zjl9959/algviz/issues)πŸ‘ˆ here.*\n", + "\n", + "## References\n", + "\n", + "+ https://algviz.com/en/MergeSort/\n", + "+ https://algviz.com/en/RecursiveTree/" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import algviz\n", + "\n", + "class MergeSort():\n", + " def __init__(self, nums_):\n", + " self.viz = algviz.Visualizer(2.0)\n", + " self.nums = self.viz.createVector(nums_, name='Numbers', cell_size=(40, 200), histogram=True)\n", + " self.merge_list = self.viz.createVector(name='Merge list', show_index=False)\n", + " self.tree = algviz.RecursiveTree(self.viz)\n", + " self.solve(0, len(nums_))\n", + " \n", + " def solve(self, l, r):\n", + " if l < r - 1:\n", + " self.tree.forward('{}:{}'.format(l, r))\n", + " m = (l + r)//2\n", + " self.solve(l, m)\n", + " self.solve(m, r)\n", + " self.nums.mark(algviz.color_gray, 0, l, hold=True)\n", + " if r < len(self.nums):\n", + " self.nums.mark(algviz.color_gray, r, len(self.nums), hold=True)\n", + " self.merge(l, m, r)\n", + " self.tree.backward()\n", + " self.nums.removeMark(algviz.color_gray)\n", + " \n", + " def merge(self, l, m, r):\n", + " # Take out the smaller elements in the subsequence in turn and place them in the merge_list.\n", + " ll = l; mm = m\n", + " self.viz.display()\n", + " while ll < m and mm < r:\n", + " if self.nums[ll] > self.nums[mm]:\n", + " self.merge_list.append(self.nums[mm])\n", + " self.nums.mark(algviz.color_gold, mm); self.nums.mark(algviz.color_dark_green, ll)\n", + " self.merge_list.mark(algviz.color_gold, len(self.merge_list)-1); self.viz.display()\n", + " mm += 1; self.viz.display(1)\n", + " else:\n", + " self.merge_list.append(self.nums[ll])\n", + " self.nums.mark(algviz.color_gold, ll); self.nums.mark(algviz.color_dark_green, mm)\n", + " self.merge_list.mark(algviz.color_gold, len(self.merge_list)-1); self.viz.display()\n", + " ll += 1; self.viz.display(1)\n", + " while ll < m:\n", + " self.merge_list.append(self.nums[ll])\n", + " self.nums.mark(algviz.color_gold, ll)\n", + " self.merge_list.mark(algviz.color_gold, len(self.merge_list)-1); self.viz.display()\n", + " ll += 1; self.viz.display(1)\n", + " while mm < r:\n", + " self.merge_list.append(self.nums[mm])\n", + " self.nums.mark(algviz.color_gold, mm)\n", + " self.merge_list.mark(algviz.color_gold, len(self.merge_list)-1); self.viz.display()\n", + " mm += 1; self.viz.display(1)\n", + " # Copies the merge_list into the origin subsequence to be resolved.\n", + " self.viz.display()\n", + " for i in range(l, r):\n", + " self.merge_list.mark(algviz.color_spring_green, 0)\n", + " self.nums[i] = self.merge_list.pop(0)\n", + " self.nums.mark(algviz.color_spring_green, i)\n", + " self.viz.display()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Numbers:" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "Generated by algviz-0.2.2(see https://algviz.com).-2-11334450123456" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "Merge list:" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "Generated by algviz-0.2.2(see https://algviz.com).5" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "Recursive tree:" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "0:70:33:71:33:55:7Generated by algviz-0.2.2(see https://algviz.com)." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "input_nums = [5, 3, -2, 3, -1, 1, 4]\n", + "solver = MergeSort(input_nums)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + }, + "vscode": { + "interpreter": { + "hash": "ba530876bec2e6283b9bacba891681e9dff395534db17e3ec46729d6d41aa6cf" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Algorithm/algviz/NQueens.ipynb b/Algorithm/algviz/NQueens.ipynb new file mode 100644 index 0000000..8721f8c --- /dev/null +++ b/Algorithm/algviz/NQueens.ipynb @@ -0,0 +1,124 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Description\n", + "\n", + "This notebook shows the algorithm running process to solves the [NQueens](https://leetcode.com/problems/n-queens/) problem.\n", + "\n", + "You can try to change the size of the checkerboard(**N**) and see the algorithm's backtracking process.\n", + "\n", + "## How to run?\n", + "\n", + "All the animations in this notebook are rendered by the [algviz](https://algviz.com/) algorithm animation engine in real time. You can follow this [guidance](https://algviz.com/en/installation.html) to set up your local environment or run this repo on Gitpod directly.\n", + "\n", + "*If you meet any problem, please report an πŸ‘‰[issue](https://github.com/zjl9959/algviz/issues)πŸ‘ˆ here.*" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "Generated by algviz-0.2.2(see https://algviz.com).πŸ‘‘β”01230123rc" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import algviz\n", + "N = 4 # The size of the checkerboard\n", + "viz = algviz.Visualizer(1)\n", + "board = viz.createTable(N, N)\n", + "cursor_row = viz.createCursor(name='r')\n", + "cursor_col = viz.createCursor(name='c')\n", + "board[cursor_row][cursor_col]\n", + "\n", + "def draw_board_background():\n", + " for r in range(N):\n", + " for c in range(N):\n", + " if (r + c) % 2:\n", + " board.mark(algviz.color_gray, r, c, True)\n", + "\n", + "def solve_queen(queen_row_pos, col_has_queen, cur_row):\n", + " if cur_row == N:\n", + " for r in range(N):\n", + " board.mark(algviz.color_green, r, queen_row_pos[r])\n", + " viz.display(3)\n", + " return\n", + " cursor_row << cur_row\n", + " for c in range(0, N):\n", + " cursor_col << c\n", + " board[cur_row][c] = '❔'\n", + " viz.display()\n", + " if col_has_queen[c] == False:\n", + " conflict = False\n", + " for r in range(0, cur_row):\n", + " if queen_row_pos[r] - c == r - cur_row or c - queen_row_pos[r] == r - cur_row:\n", + " board.mark(algviz.color_red, r, queen_row_pos[r])\n", + " board.mark(algviz.color_red, cur_row, c)\n", + " viz.display(0.5)\n", + " conflict = True\n", + " break\n", + " if not conflict:\n", + " queen_row_pos[cur_row] = c\n", + " col_has_queen[c] = True\n", + " board[cur_row][c] = 'πŸ‘‘'\n", + " viz.display()\n", + " solve_queen(queen_row_pos, col_has_queen, cur_row+1)\n", + " col_has_queen[c] = False\n", + " board[cur_row][c] = ''\n", + " cursor_row << cur_row\n", + " else:\n", + " board[cur_row][c] = ''\n", + " else:\n", + " for r in range(cur_row):\n", + " if queen_row_pos[r] == c:\n", + " board.mark(algviz.color_red, r, c)\n", + " break\n", + " board.mark(algviz.color_red, cur_row, c)\n", + " viz.display(0.5)\n", + " board[cur_row][c] = ''\n", + "\n", + "draw_board_background()\n", + "solve_queen([-1 for _ in range(N)], [False for _ in range(N)], 0)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + }, + "vscode": { + "interpreter": { + "hash": "ba530876bec2e6283b9bacba891681e9dff395534db17e3ec46729d6d41aa6cf" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Algorithm/algviz/Prim.ipynb b/Algorithm/algviz/Prim.ipynb new file mode 100644 index 0000000..9412808 --- /dev/null +++ b/Algorithm/algviz/Prim.ipynb @@ -0,0 +1,201 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Prim algorithm\n", + "\n", + "**Prim's algorithm is a greedy algorithm that finds a [minimum spanning tree](https://en.wikipedia.org/wiki/Minimum_spanning_tree) for a weighted undirected graph.**\n", + "\n", + "The algorithm consists of the following steps:\n", + "\n", + "1. Initialize a tree with a single vertex, chosen arbitrarily from the graph.\n", + "\n", + "2. Grow the tree by one edge: of the edges that connect the tree to vertices not yet in the tree, find the minimum-weight edge, and transfer it to the tree.\n", + "\n", + "3. Repeat step 2 (until all vertices are in the tree).\n", + "\n", + "## How to run?\n", + "\n", + "All the animations in this notebook are rendered by the [algviz](https://algviz.com/) algorithm animation engine in real time. You can follow this [guidance](https://algviz.com/en/installation.html) to set up your local environment or run this repo on Gitpod directly.\n", + "\n", + "*If you meet any problem, please report an πŸ‘‰[issue](https://github.com/zjl9959/algviz/issues)πŸ‘ˆ here.*\n", + "\n", + "## Reference\n", + "\n", + "https://en.wikipedia.org/wiki/Prim%27s_algorithm" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import algviz\n", + "\n", + "class PrimAlgorithm:\n", + " def __init__(self, graph_nodes):\n", + " self.viz = algviz.Visualizer(0.5)\n", + " self.graph = self.viz.createGraph(graph_nodes, name='Input graph', directed=False)\n", + " self.nodes_num = len(graph_nodes)\n", + " self.graph_nodes = graph_nodes\n", + " self.tree_nodes = list()\n", + " for node in graph_nodes.values():\n", + " self.tree_nodes.append(node)\n", + " self.graph.markNode(algviz.cTomato, node, True)\n", + " break\n", + " self.viz.display()\n", + "\n", + " def solve(self):\n", + " used_edges = list()\n", + " while len(self.tree_nodes) < self.nodes_num:\n", + " min_edge = None; min_node1 = None; min_node2 = None\n", + " for node in self.tree_nodes:\n", + " for (neighbor, edge) in node.neighbors():\n", + " if neighbor not in self.tree_nodes:\n", + " if min_edge == None or edge < min_edge:\n", + " min_edge = edge\n", + " min_node1 = node; min_node2 = neighbor\n", + " if min_edge == None:\n", + " return False\n", + " self.graph.markNode(algviz.cTomato, min_node2, True)\n", + " self.graph.markEdge(algviz.cRed, min_node1, min_node2, True)\n", + " used_edges.append((min_node1, min_node2))\n", + " self.tree_nodes.append(min_node2)\n", + " self.viz.display()\n", + " self.graph.removeMark(algviz.cTomato)\n", + " for node in self.graph_nodes.values():\n", + " for (neighbor, edge) in node.neighbors():\n", + " if (node, neighbor) not in used_edges:\n", + " node.remove(neighbor)\n", + " self.viz.display(3)\n", + " return True" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Input graph:" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "012233462Generated by algviz-0.2.2(see https://algviz.com).232" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nodes1 = [i for i in range(4)]\n", + "edges1 = [(0, 1, 2), (0, 3, 4), (2, 1, 3), (2, 3, 2), (3, 1, 6)]\n", + "graph_nodes1 = algviz.parseGraph(nodes1, edges1, directed=False)\n", + "\n", + "solver1 = PrimAlgorithm(graph_nodes1)\n", + "solver1.solve()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Input graph:" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "025321663553728454493721Generated by algviz-0.2.2(see https://algviz.com).221423334" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "nodes2 = [i for i in range(10)]\n", + "edges2 = [\n", + " (0, 1, 6), (0, 2, 5), (0, 3, 2), (2, 4, 4), (6, 5, 3),\n", + " (1, 6, 3), (2, 7, 5), (3, 8, 2), (3, 9, 1), (7, 6, 2),\n", + " (4, 8 ,7), (7, 8, 4), (9, 2, 3), (5, 1, 5)\n", + "]\n", + "graph_nodes2 = algviz.parseGraph(nodes2, edges2, directed=False)\n", + "\n", + "solver2 = PrimAlgorithm(graph_nodes2)\n", + "solver2.solve()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + }, + "vscode": { + "interpreter": { + "hash": "ba530876bec2e6283b9bacba891681e9dff395534db17e3ec46729d6d41aa6cf" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Algorithm/algviz/QuickSort.ipynb b/Algorithm/algviz/QuickSort.ipynb new file mode 100644 index 0000000..595c0e4 --- /dev/null +++ b/Algorithm/algviz/QuickSort.ipynb @@ -0,0 +1,140 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Quick sort algorithm\n", + "\n", + "## Description\n", + "\n", + "The Quicksort algorithm was first proposed by Charles Antony Richard Hoare, also called the partition-exchange sort algorithm.\n", + "The Quicksort algorithm has high execution efficiency in general and is widely used in practical engineering.\n", + "For more description, please refer to this [blog](https://algviz.com/en/QuickSort/#fundamental).\n", + "\n", + "You can try to change the `input_nums` and run the cells below.\n", + "\n", + "## How to run?\n", + "\n", + "All the animations in this notebook are rendered by the [algviz](https://algviz.com/) algorithm animation engine in real time. You can follow this [guidance](https://algviz.com/en/installation.html) to set up your local environment or run this repo on Gitpod directly.\n", + "\n", + "*If you meet any problem, please report an πŸ‘‰[issue](https://github.com/zjl9959/algviz/issues)πŸ‘ˆ here.*" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import algviz\n", + "\n", + "class QuickSort():\n", + " def __init__(self, nums_):\n", + " self.viz = algviz.Visualizer(1.0, layout=True)\n", + " self.nums = self.viz.createVector(nums_, name='Numbers', cell_size=(40,200), histogram=True)\n", + " self.tree = algviz.RecursiveTree(self.viz)\n", + " self.p = self.viz.createCursor(name='P'); self.nums[self.p]\n", + " self.solve(0, len(nums_))\n", + " self.viz.display(3.0); self.viz.layout()\n", + " \n", + " def solve(self, l, r):\n", + " if l >= r - 1:\n", + " return # Basic situation: just one element left in the subsequence.\n", + " self.tree.forward('{}:{}'.format(l, r-1))\n", + " self.nums.mark(algviz.color_gray, 0, l, hold=True)\n", + " if r < len(self.nums):\n", + " self.nums.mark(algviz.color_gray, r, len(self.nums), hold=True)\n", + " i = l; self.p << l; self.viz.display()\n", + " # Subsequence segmentation beigin.\n", + " while i < r - 1:\n", + " if self.nums[i] < self.nums[r-1]:\n", + " self.nums.mark(algviz.color_orange, r-1); self.nums.mark(algviz.color_tomato, i); self.viz.display(1.0)\n", + " self.nums.swap(i, self.p); self.viz.display(2.0)\n", + " self.nums.mark(algviz.color_silver, self.p, hold=True); self.p += 1\n", + " else:\n", + " self.nums.mark(algviz.color_orange, r-1); self.nums.mark(algviz.color_lime, i); self.viz.display()\n", + " self.nums.mark(algviz.color_silver, i, hold=True)\n", + " i += 1; self.viz.display(1.0)\n", + " self.nums.swap(self.p, r-1); self.viz.display(2.0)\n", + " # Subsequence segmentation end.\n", + " self.nums.removeMark(algviz.color_gray); self.nums.removeMark(algviz.color_silver)\n", + " self.solve(l, self.p.index())\n", + " self.solve(self.p + 1, r)\n", + " self.tree.backward()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P3-4-14-6-320123456P0:60:60:60:60:60:60:60:60:60:60:60:60:60:60:60:60:60:60:60:30:60:30:60:30:60:30:60:30:60:30:60:30:60:30:60:30:60:30:60:30:10:60:30:10:60:30:10:60:30:10:60:30:11:30:60:30:11:30:60:30:11:30:60:30:11:30:60:30:11:30:60:30:11:30:60:30:11:30:60:30:11:30:60:30:11:31:20:60:30:11:31:20:60:30:11:31:20:60:30:11:31:20:60:30:11:31:20:60:30:11:31:23:60:60:33:60:11:31:20:60:33:60:11:31:20:60:33:60:11:31:20:60:33:60:11:31:20:60:33:60:11:31:20:60:33:60:11:31:20:60:33:60:11:31:20:60:33:60:11:31:20:60:33:60:11:31:20:60:33:60:11:31:23:40:60:33:60:11:31:23:40:60:33:60:11:31:23:40:60:33:60:11:31:23:40:60:33:60:11:31:23:40:60:33:60:11:31:23:45:60:60:33:60:11:31:23:45:60:60:33:60:11:31:23:45:60:60:33:60:11:31:23:45:60:60:33:60:11:31:23:45:60:60:33:60:11:31:23:45:6 Make your Python code alive A L Z G V I Numbers:Recursive tree:" + ], + "text/plain": [ + "" + ] + }, + "metadata": { + "image/svg+xml": { + "duration": 125, + "frames": 66, + "layout": { + "0": [ + 5, + 5, + 304, + 237 + ], + "1": [ + 314, + 5, + 226, + 278 + ] + }, + "size": [ + 545, + 306 + ] + } + }, + "output_type": "display_data" + } + ], + "source": [ + "input_nums = [3, -4, -1, 4, -6, -3, 2]\n", + "solver = QuickSort(input_nums)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.16" + }, + "vscode": { + "interpreter": { + "hash": "ba530876bec2e6283b9bacba891681e9dff395534db17e3ec46729d6d41aa6cf" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Algorithm/algviz/ReverseLinkedList.ipynb b/Algorithm/algviz/ReverseLinkedList.ipynb new file mode 100644 index 0000000..f61225f --- /dev/null +++ b/Algorithm/algviz/ReverseLinkedList.ipynb @@ -0,0 +1,98 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Reverse linked list\n", + "\n", + "Solve the leetcode problem [reverse-linked-list](https://leetcode.com/problems/reverse-linked-list/).\n", + "\n", + "## Solution\n", + "\n", + "Scan the linked list from head to tail.\n", + "\n", + "Use the `h1` and `h2` pointers to record the two adjacent nodes.\n", + "\n", + "Do the \"h2->h2\" to \"h1<-h2\" operation while scanning.\n", + "\n", + "## How to run?\n", + "\n", + "All the animations in this notebook are rendered by the [algviz](https://algviz.com/) algorithm animation engine in real time. You can follow this [guidance](https://algviz.com/en/installation.html) to set up your local environment or run this repo on Gitpod directly.\n", + "\n", + "*If you meet any problem, please report an πŸ‘‰[issue](https://github.com/zjl9959/algviz/issues)πŸ‘ˆ here.*" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "1234567Generated by algviz-0.2.2(see https://algviz.com)." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import algviz\n", + "\n", + "def reverse_linked_list(data):\n", + " # Create a visualizer object.\n", + " viz = algviz.Visualizer(1)\n", + " # Create and display a forward linked list.\n", + " head = algviz.parseForwardLinkedList(data)\n", + " graph = viz.createGraph(head)\n", + " viz.display(1)\n", + " # before h1->h2, after h1<-h2\n", + " h1 = None\n", + " h2 = head\n", + " while h2 is not None:\n", + " temp = h2.next\n", + " h2.next = h1\n", + " h1 = h2\n", + " h2 = temp\n", + " graph.markNode(algviz.cGold, h1)\n", + " graph.markNode(algviz.cAqua, h2)\n", + " viz.display()\n", + " viz.display()\n", + "\n", + "data = [1, 2, 3, 4, 5, 6, 7]\n", + "reverse_linked_list(data)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + }, + "vscode": { + "interpreter": { + "hash": "ba530876bec2e6283b9bacba891681e9dff395534db17e3ec46729d6d41aa6cf" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Algorithm/algviz/TrieTree.ipynb b/Algorithm/algviz/TrieTree.ipynb new file mode 100644 index 0000000..44529ec --- /dev/null +++ b/Algorithm/algviz/TrieTree.ipynb @@ -0,0 +1,214 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# TrieTree\n", + "\n", + "This notebook shows how to construct a [trie tree](https://en.wikipedia.org/wiki/Trie) with a list of known strings and then shows how to use the trie tree to match a given string.\n", + "\n", + "## How to run?\n", + "\n", + "All the animations in this notebook are rendered by the [algviz](https://algviz.com/) algorithm animation engine in real time. You can follow this [guidance](https://algviz.com/en/installation.html) to set up your local environment or run this repo on Gitpod directly.\n", + "\n", + "*If you meet any problem, please report an πŸ‘‰[issue](https://github.com/zjl9959/algviz/issues)πŸ‘ˆ here.*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import algviz\n", + "\n", + "class TrieTree:\n", + " def __init__(self, str_list):\n", + " self.viz = algviz.Visualizer(1)\n", + " table_cols = 0\n", + " for s in str_list:\n", + " table_cols = max(table_cols, len(s))\n", + " self.table = self.viz.createTable(len(str_list), table_cols, str_list, 'String list to construct trie tree', cell_size=(20, 20))\n", + " self.root = algviz.TreeNode('root')\n", + " self.graph = self.viz.createGraph(self.root)\n", + " self.s = self.viz.createVector(name='String to match', cell_size=(20, 20))\n", + " self.construct(str_list)\n", + "\n", + " def construct(self, str_list):\n", + " for i in range(len(str_list)):\n", + " cur = self.root\n", + " for j in range(len(str_list[i])):\n", + " child_pos = None\n", + " for child in cur.children():\n", + " if str(child) == str_list[i][j]:\n", + " child_pos = child\n", + " break\n", + " if not child_pos:\n", + " child_pos = algviz.TreeNode(str_list[i][j])\n", + " cur.add(child_pos)\n", + " cur = child_pos\n", + " self.table.mark(algviz.cAqua, i, j)\n", + " self.graph.markNode(algviz.cAqua, cur)\n", + " self.viz.display()\n", + " self.viz.display()\n", + "\n", + " def match(self, s):\n", + " self.graph.removeMark(algviz.cLime)\n", + " self.s.clear()\n", + " for c in s:\n", + " self.s.append(c)\n", + " cur = self.root\n", + " i = 0\n", + " while i < len(s):\n", + " match = False\n", + " self.s.removeMark(algviz.cLime)\n", + " self.s.mark(algviz.cLime, i, True)\n", + " for child in cur.children():\n", + " if child.val == s[i]:\n", + " cur = child\n", + " i += 1\n", + " match = True\n", + " self.graph.markNode(algviz.cLime, cur, True)\n", + " self.viz.display()\n", + " break\n", + " else:\n", + " self.graph.markNode(algviz.cSilver, child)\n", + " self.viz.display(0.5)\n", + " if not match:\n", + " return False\n", + " return i == len(s)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "String list to construct trie tree:" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "Generated by algviz-0.2.2(see https://algviz.com).abcabdbcdbce0123012" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "rootabbcdcdeGenerated by algviz-0.2.2(see https://algviz.com)." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "String to match:" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "Generated by algviz-0.2.2(see https://algviz.com).012bca" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Construct a tire tree.\n", + "str_list = ['abc', 'abd', 'bcd', 'bce']\n", + "trie_tree = TrieTree(str_list)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Match str:abd result is:True\n" + ] + } + ], + "source": [ + "# Match a string: True case\n", + "s1 = 'abd'\n", + "print('Match str:{} result is:{}'.format(s1, trie_tree.match(s1)))" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Match str:bca result is:False\n" + ] + } + ], + "source": [ + "# Match a string: False case\n", + "s2 = 'bca'\n", + "print('Match str:{} result is:{}'.format(s2, trie_tree.match(s2)))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + }, + "vscode": { + "interpreter": { + "hash": "ba530876bec2e6283b9bacba891681e9dff395534db17e3ec46729d6d41aa6cf" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/requirements.txt b/requirements.txt index 54de05f..4494aca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,4 +12,5 @@ tabulate scikit-fuzzy pillow beautifulsoup4 -skia-python \ No newline at end of file +skia-python +algviz>=0.3.0 \ No newline at end of file