├── .gitignore ├── README.md ├── chapter_02_basic_sort ├── __init__.py ├── insertion_sort.py ├── main.py └── selection_sort.py ├── chapter_03_advanced_sort ├── __init__.py ├── main.py ├── merge_sort.py └── quick_sort.py ├── chapter_04_heap_sort ├── __init__.py ├── heap_sort.py └── main.py ├── chapter_05_binary_search ├── __init__.py ├── binary_search.py ├── main.py └── shakespeare.txt ├── chapter_06_union_find ├── __init__.py ├── main.py └── union_find.py ├── chapter_07_graph ├── __init__.py ├── component.py ├── dense_graph.py ├── main.py ├── path.py ├── shortest_path.py ├── sparse_graph.py ├── testG.txt ├── testG1.txt └── testG2.txt ├── chapter_08_minimum_span_tree ├── __init__.py ├── dense_graph.py ├── edge.py ├── kruskal_mst.py ├── lazy_prim_heap.py ├── lazy_prim_mst.py ├── main.py ├── sparse_graph.py ├── testG1.txt ├── testG2.txt ├── testG3.txt └── testG4.txt ├── chapter_09_shortest_path ├── __init__.py ├── bellman_ford.py ├── dijkstra.py ├── main.py ├── testG1.txt └── testG2.txt └── sort_test_helper ├── __init__.py └── helpers.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## play-with-data-structures 2 | 3 | Python implementation of imooc course [学习算法思想,修炼编程内功](http://coding.imooc.com/class/71.html), thanks for that great course (instructor [liuyubobobo](https://github.com/liuyubobobo)) ! 4 | 5 | Any pull-request is welcome:) 6 | 7 | Any quesitons please email to wangzhe.dut@gmail.com 8 | 9 | 10 | ### Some course notes 11 | 12 | 1. 选择排序 13 | - 从当前未排序的序列中选择最小的值 14 | 15 | 16 | 2. 插入排序 17 | - 将当前处理的元素插入到前面排好的位置上,对于近乎有序的数组复杂度为O(n), can be used for shell sort. 18 | 19 | 20 | 3. 冒泡排序 21 | - move the largest element to the end of the array everytime 22 | 23 | 24 | 4. Merge sort 25 | - 需要O(n)的空间复杂度 26 | - 小数据使用insertion_sort 27 | - 也可以自底向上归并排序, 可以在nlog(n)时间内对链表进行排序(因为不需要用到数组索引)!!! 28 | 29 | 30 | 5. 快速排序 31 | - 对近乎有序的数组排序效率很差,退化成O(n^2)。解决方案:随机化选择pivot 32 | - 对重复元素多的数组排序效率很差。解决方案:双路(三路)快排 33 | - 双路排序是分出了大于和小于pivot_value的两部分,三路排序是加上了等于pivot_value的部分 34 | 35 | 36 | 6. Heap sort 37 | - shift up 38 | - shift down 39 | - heapify 所有的叶子节点可以看成是最大堆,第一个非叶子节点是最后一个叶子节点的index除以2(index // 2),对每一个非叶子节点(反向)进行shift_down即可 40 | - 一个个插入空堆,时间复杂度是O(nlogn),heapify是O(n) !!!! 因为上来就抛弃了近乎一半的叶子节点 41 | - 可以原地堆排序优化(空间优化),空间复杂度O(1) 42 | - 现将最大的值放在数组最后一个位置,再与第一个位置交换并shift_down 43 | - 快排额外空间是O(logn) 44 | - 插入,归并是稳定排序;快排和堆排是不稳定排序,可以自定义比较函数,让排序算法不存在稳定性问题。 45 | - 索引堆(Index Heap)新建一个索引数组,不用移动原始数组,而改变索引数组即可(典型的空间换时间策略),适合于复杂元素数组(move cost比较大的) 46 | - 应用场景:动态优先级的情况 47 | - 多路归并排序: 比如4路,每次将4个元素推入堆中,n路归并退化成堆排序 48 | - d叉堆(d-ary heap):每个元素可以有3个孩子 49 | - 思路:最大最小队列(同时维护一个最大堆和一个最小堆) 50 | - 二项堆,斐波那契堆 51 | 52 | 53 | 7. 二分查找 54 | - 对于有序的数列才能使用二分查找 55 | - floor and ceil 56 | 57 | 58 | 8. 并查集 59 | - 解决的是连接问题(而不是路径问题),少了很多信息,因此可以更高效的回答。 60 | - 并查集的操作时间复杂度近乎是O(1)的 61 | 62 | 63 | 9. Graph 64 | - 无向图(Undirected Graph) 65 | - 有向图(Directed Graph) 66 | - 无权图(Unweighted Graph) 67 | - 有权图(Weighted Graph) 68 | - 图的连通性(图中的点不一定都是连在一起的) 69 | - 自环边(self-loop) 70 | - 平行边(parallel-edges) 71 | - 简单图(没有自环边和平行边) 72 | - 图的表示:邻接矩阵(Adjacency Matrix,适合稠密图),邻接表(Adjacency Lists,适合稀疏图) 73 | - DFS -> 稀疏图(邻接表):O(V+E) 74 | - DFS -> 稠密图(邻接矩阵):O(V^2) 75 | - 广度优先:在加入队列之前时刻判断是否应该加入队列,可以用来找最短距离,先遍历到的点的距离一定小于等于后遍历到的点的距离 76 | - 广度优先复杂度和深度优先的复杂度一致 77 | - flood fill算法(PS抠图) 78 | - 二分图(买方,卖方,路径是达成交易的价格) 79 | - 带权图(weighted graph) 80 | 81 | 82 | 9. Minimum Span Tree 83 | - 是否存在一棵树,能够连接所有的点,并且路径之和最小? 84 | - 带权无向图(连通图) 85 | - 找V-1条边,连接V个顶点,总权值最小 86 | - Cut Property(切分定理),把图中的节点分成两部分,成为一个切分 87 | - 横切边(连接两个切分的边) 88 | - 给定任意切分,横切边中权值最小的边必然属于最小生成树 89 | - Prim算法:从任意一个点开始,加上weight最小的边(到一个最小堆中)和节点,类似贪心思路, 优化后从O(logE)到O(ElogV) 90 | - Kruskal:扫描所有的边(从小到大),只要不能变成环,就是一条边 O(ElogE) 91 | 92 | 93 | 10. 最短路径问题 94 | - 单源最短路径:single source shortest path 95 | - 有权图的松弛操作:找到一条更短的路径(尽管可能多经过了点,更“松”的路径). 96 | - 每遍历一个点,都考虑一下经过这个点是否可能让路径长度更低。 97 | - dijkstra:有向图单源最短路径算法(图中不能有负权边), O(ElogV),求的是起始点到所有点最短的路径 98 | - 处理负权边(有时候会产生负权环 -> 会导致没有最短路径) 99 | - Bellman-Ford (前提图中不能负权环,但该算法可以判断图中是否有负权环), O(EV) 100 | - 如果一个图没有负权环,从一点到另一个点的最短路径,最多经过的V个顶点,有V-1条边。否则,存在顶点经过了两次,即存在负权环。 101 | - 依旧找最短的边,但是此时最短边并不能保证全局最短(因为有负权),可以对所有的点进行第二次松弛操作。 102 | - 理论上对所有的点进行V-1次松弛操作,理论上就找到了从原点到其他所有点的最短路径。如果还可以继续松弛,即说明图中有负权环。 103 | - 有向无环图(DAG)可以用拓扑排序O(V+E) 104 | - Floyed算法O(V^3),处理无负权环的图,动态规划思想 105 | 106 | 11. 杂项 107 | - 分治 108 | - 贪心 109 | - 递归回溯 110 | - DP -------------------------------------------------------------------------------- /chapter_02_basic_sort/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwang96-dl/play-with-algorithms/fa34ae2c17e75b3d233b1426094ce66229090a37/chapter_02_basic_sort/__init__.py -------------------------------------------------------------------------------- /chapter_02_basic_sort/insertion_sort.py: -------------------------------------------------------------------------------- 1 | from sort_test_helper.helpers import generate_random_array 2 | from sort_test_helper.helpers import test_sort 3 | 4 | 5 | def insertion_sort(arr): 6 | for i in range(1, len(arr)): 7 | # 寻找元素arr[i]合适的插入位置 8 | temp = arr[i] 9 | index = i 10 | for j in range(i, 0, -1): 11 | if temp < arr[j - 1]: 12 | arr[j] = arr[j - 1] 13 | index = j - 1 14 | else: 15 | break 16 | arr[index] = temp 17 | 18 | def insertion_sort_in_range(arr, l, r): 19 | for i in range(l + 1, r + 1): 20 | # 寻找元素arr[i]合适的插入位置 21 | temp = arr[i] 22 | index = i 23 | for j in range(i, l, -1): 24 | if temp < arr[j - 1]: 25 | arr[j] = arr[j - 1] 26 | index = j - 1 27 | else: 28 | break 29 | arr[index] = temp 30 | -------------------------------------------------------------------------------- /chapter_02_basic_sort/main.py: -------------------------------------------------------------------------------- 1 | from sort_test_helper.helpers import generate_random_array 2 | from sort_test_helper.helpers import generate_nearly_ordered_random_array 3 | from sort_test_helper.helpers import test_sort 4 | from chapter_02_basic_sort.selection_sort import selection_sort 5 | from chapter_02_basic_sort.insertion_sort import insertion_sort 6 | 7 | 8 | if __name__ == '__main__': 9 | n = 10000 10 | arr1 = generate_random_array(n, 0, n) 11 | 12 | test_sort('selection_sort', selection_sort, arr1[:]) 13 | test_sort('insertion_sort', insertion_sort, arr1[:]) 14 | 15 | arr2 = generate_nearly_ordered_random_array(n, 0, n, 1) 16 | test_sort('selection_sort (nearly sorted array)', selection_sort, arr2[:]) 17 | test_sort('insertion_sort (nearly sorted array)', insertion_sort, arr2[:]) -------------------------------------------------------------------------------- /chapter_02_basic_sort/selection_sort.py: -------------------------------------------------------------------------------- 1 | from sort_test_helper.helpers import generate_random_array 2 | from sort_test_helper.helpers import test_sort 3 | 4 | 5 | def selection_sort(arr): 6 | for i in range(len(arr)): 7 | min_index = i 8 | for j in range(i + 1, len(arr)): 9 | if arr[j] < arr[min_index]: 10 | min_index = j 11 | arr[i], arr[min_index] = arr[min_index], arr[i] 12 | -------------------------------------------------------------------------------- /chapter_03_advanced_sort/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwang96-dl/play-with-algorithms/fa34ae2c17e75b3d233b1426094ce66229090a37/chapter_03_advanced_sort/__init__.py -------------------------------------------------------------------------------- /chapter_03_advanced_sort/main.py: -------------------------------------------------------------------------------- 1 | from sort_test_helper.helpers import generate_random_array 2 | from sort_test_helper.helpers import generate_nearly_ordered_random_array 3 | from sort_test_helper.helpers import test_sort 4 | from chapter_02_basic_sort.insertion_sort import insertion_sort 5 | from chapter_03_advanced_sort.merge_sort import merge_sort 6 | from chapter_03_advanced_sort.merge_sort import merge_sort_bu 7 | from chapter_03_advanced_sort.quick_sort import quick_sort 8 | from chapter_03_advanced_sort.quick_sort import quick_sort2 9 | from chapter_03_advanced_sort.quick_sort import quick_sort_3_ways 10 | 11 | 12 | if __name__ == '__main__': 13 | n = 10000 14 | arr1 = generate_random_array(n, 0, n) 15 | 16 | test_sort('merge_sort', merge_sort, arr1[:]) 17 | test_sort('merge_sort_bu', merge_sort_bu, arr1[:]) 18 | # test_sort('insertion_sort', insertion_sort, arr1[:]) 19 | test_sort('quick_sort', quick_sort, arr1[:]) 20 | 21 | arr2 = generate_nearly_ordered_random_array(n, 0, n, 10) 22 | test_sort('merge_sort', merge_sort, arr2[:]) 23 | test_sort('merge_sort_bu', merge_sort_bu, arr2[:]) 24 | # 退化到O(n^2)的概率非常非常小 25 | test_sort('quick_sort', quick_sort, arr2[:]) 26 | 27 | arr2 = generate_random_array(n, 0, 10) 28 | test_sort('merge_sort', merge_sort, arr2[:]) 29 | test_sort('merge_sort_bu', merge_sort_bu, arr2[:]) 30 | # 退化到O(n^2)的概率非常非常小 31 | test_sort('quick_sort', quick_sort, arr2[:]) 32 | test_sort('quick_sort2', quick_sort2, arr2[:]) 33 | test_sort('quick_sort_3_ways', quick_sort_3_ways, arr2[:]) -------------------------------------------------------------------------------- /chapter_03_advanced_sort/merge_sort.py: -------------------------------------------------------------------------------- 1 | from chapter_02_basic_sort.insertion_sort import insertion_sort_in_range 2 | 3 | 4 | def merge_sort(arr): 5 | __merge_sort(arr, 0, len(arr) - 1) 6 | 7 | def __merge_sort(arr, l, r): 8 | """递归使用归并排序,对arr[l...r]的范围进行排序""" 9 | if r - l <= 15: 10 | insertion_sort_in_range(arr, l, r) 11 | return 12 | mid = l + (r - l) // 2 13 | __merge_sort(arr, l, mid) 14 | __merge_sort(arr, mid + 1, r) 15 | __merge(arr, l, mid, r) 16 | 17 | def __merge(arr, l, mid, r): 18 | """将arr[l...mid]和arr[mid+1...r]两部分进行归并""" 19 | aux = [arr[i] for i in range(l, r + 1)] 20 | i, j = l, mid + 1 21 | for k in range(l, r + 1): 22 | if i > mid: 23 | arr[k] = aux[j - l] 24 | j += 1 25 | elif j > r: 26 | arr[k] = aux[i - l] 27 | i += 1 28 | elif aux[i - l] < aux[j - l]: 29 | arr[k] = aux[i - l] 30 | i += 1 31 | else: 32 | arr[k] = aux[j - l] 33 | j += 1 34 | 35 | def merge_sort_bu(arr): 36 | """自底向上的归并排序""" 37 | sz = 1 38 | while sz <= len(arr): 39 | i = 0 40 | while i + sz < len(arr): 41 | # 对arr[i...i+sz-1]和arr[i+sz...i+2*sz-1] 42 | __merge(arr, i, i + sz - 1, min(i + 2 * sz - 1, len(arr) - 1)) 43 | i += 2 * sz 44 | sz += sz 45 | -------------------------------------------------------------------------------- /chapter_03_advanced_sort/quick_sort.py: -------------------------------------------------------------------------------- 1 | import random 2 | from time import time 3 | 4 | from chapter_02_basic_sort.insertion_sort import insertion_sort_in_range 5 | 6 | 7 | def quick_sort(arr): 8 | random.seed(time()) 9 | __quick_sort(arr, 0, len(arr) - 1) 10 | 11 | def __quick_sort(arr, l, r): 12 | """对arr[l...r]前闭后闭部分进行快速排序""" 13 | if l >= r: 14 | return 15 | p = __partition(arr, l, r) 16 | __quick_sort(arr, l, p - 1) 17 | __quick_sort(arr, p + 1, r) 18 | 19 | def __partition(arr, l, r): 20 | """ 21 | 对arr[l...r]前闭后闭部分进行partition操作, 22 | 返回p, 使得arr[l...p-1] < arr[p], 并且arr[p+1...r] > arr[p] 23 | """ 24 | _random_index = random.randint(l, r) 25 | arr[l], arr[_random_index] = arr[_random_index], arr[l] 26 | pivot_value = arr[l] 27 | # arr[l+1...j] < pivot_value; arr[j+1...i) > pivot_value 28 | j = l 29 | for i in range(l + 1, r + 1): 30 | if arr[i] < pivot_value: 31 | # now the element at j + 1 is definitely <= v!!! 32 | # so safe to swap 33 | arr[j + 1], arr[i] = arr[i], arr[j + 1] 34 | j += 1 35 | arr[l], arr[j] = arr[j], arr[l] 36 | return j 37 | 38 | def quick_sort2(arr): 39 | """双路快排 quick sort two ways""" 40 | random.seed(time()) 41 | __quick_sort2(arr, 0, len(arr) - 1) 42 | 43 | def __quick_sort2(arr, l, r): 44 | """对arr[l...r]前闭后闭部分进行快速排序""" 45 | if l >= r: 46 | return 47 | p = __partition2(arr, l, r) 48 | __quick_sort2(arr, l, p - 1) 49 | __quick_sort2(arr, p + 1, r) 50 | 51 | def __partition2(arr, l, r): 52 | """ 53 | 对arr[l...r]前闭后闭部分进行partition操作, 54 | 返回p, 使得arr[l...p-1] < arr[p], 并且arr[p+1...r] > arr[p] 55 | """ 56 | _random_index = random.randint(l, r) 57 | arr[l], arr[_random_index] = arr[_random_index], arr[l] 58 | pivot_value = arr[l] 59 | # arr[l+1...i) <= pivot_value, arr(j...r] >= pivot_value 60 | i, j = l + 1, r # initial ranges both empty 61 | while True: 62 | while i <= r and arr[i] < pivot_value: 63 | i += 1 64 | while j >= l + 1 and arr[j] > pivot_value: 65 | j -= 1 66 | if i > j: 67 | break 68 | arr[i], arr[j] = arr[j], arr[i] 69 | i += 1 70 | j -= 1 71 | arr[l], arr[j] = arr[j], arr[l] 72 | return j 73 | 74 | def quick_sort_3_ways(arr): 75 | """三路快排""" 76 | random.seed(time()) 77 | __quick_sort_3_ways(arr, 0, len(arr) - 1) 78 | 79 | def __quick_sort_3_ways(arr, l, r): 80 | """ 81 | 三路快速排序处理arr[l...r] 82 | 将arr[l...r]分为 (1) 小于pivot_value, (2) 等于pivot_value, (3) 大于pivot_value三部分 83 | 之后递归对小于pivot_value部分和大于pivot_value部分分别继续进行三路快速排序 84 | """ 85 | if r - l <= 15: 86 | insertion_sort_in_range(arr, l, r) 87 | return 88 | # partition部分 89 | _random_index = random.randint(l, r) 90 | arr[l], arr[_random_index] = arr[_random_index], arr[l] 91 | pivot_value = arr[l] 92 | lt = l # arr[l+1...lt] < pivot_value 93 | gt = r + 1 # arr[gt...r] > pivot_value 94 | i = l + 1 # arr[lt+1...i) == pivot_value, i is current index 95 | while i < gt: 96 | if arr[i] < pivot_value: 97 | arr[i], arr[lt + 1] = arr[lt + 1], arr[i] 98 | lt += 1 99 | i += 1 100 | elif arr[i] > pivot_value: 101 | arr[i], arr[gt - 1] = arr[gt - 1], arr[i] 102 | gt -= 1 103 | else: # arr[i] == pivot_value 104 | i += 1 105 | arr[l], arr[lt] = arr[lt], arr[l] 106 | __quick_sort_3_ways(arr, l, lt - 1) 107 | __quick_sort_3_ways(arr, gt, r) 108 | -------------------------------------------------------------------------------- /chapter_04_heap_sort/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwang96-dl/play-with-algorithms/fa34ae2c17e75b3d233b1426094ce66229090a37/chapter_04_heap_sort/__init__.py -------------------------------------------------------------------------------- /chapter_04_heap_sort/heap_sort.py: -------------------------------------------------------------------------------- 1 | class MaxHeap: 2 | def __init__(self, arr=None, capacity=10): 3 | if not arr: 4 | # for the convenience of indexing 5 | self._data = [None] * (capacity + 1) 6 | self._count = 0 7 | self._capacity = capacity 8 | else: 9 | n = len(arr) 10 | self._data = [None] * (n + 1) 11 | for i in range(n): 12 | self._data[i + 1] = arr[i] 13 | self._count = n 14 | self._capacity = n 15 | for i in range(self._count // 2, 0, -1): 16 | self._shift_down(i) 17 | 18 | def size(self): 19 | return self._count 20 | 21 | def is_empty(self): 22 | return self._count == 0 23 | 24 | def insert(self, item): 25 | assert (self._count + 1) <= self._capacity, 'heap is full' 26 | self._data[self._count + 1] = item 27 | self._count += 1 28 | self._shift_up(self._count) 29 | 30 | def extract_max(self): 31 | assert self._count > 0, 'can not extract_max from empty heap' 32 | ret = self._data[1] 33 | self._data[1], self._data[self._count] = self._data[self._count], self._data[1] 34 | self._count -= 1 35 | self._shift_down(1) 36 | return ret 37 | 38 | def _shift_up(self, index): 39 | # 因为是最大堆,所以父亲节点的值应该要比孩子节点的值要大的 40 | while index > 1 and self._data[index // 2] < self._data[index]: 41 | self._data[index // 2], self._data[index] = self._data[index], self._data[index // 2] 42 | index //= 2 43 | 44 | def _shift_down(self, index): 45 | while 2 * index <= self._count: 46 | j = 2 * index # 在此轮循环中,self._data[index]和self._data[j]交换位置 47 | if j + 1 <= self._count and self._data[j + 1] > self._data[j]: 48 | j += 1 49 | if self._data[index] >= self._data[j]: 50 | break 51 | self._data[index], self._data[j] = self._data[j], self._data[index] 52 | index = j 53 | 54 | 55 | class MinHeap: 56 | def __init__(self, arr=None, capacity=10): 57 | if not arr: 58 | # for the convenience of indexing 59 | self._data = [None] * (capacity + 1) 60 | self._count = 0 61 | self._capacity = capacity 62 | else: 63 | n = len(arr) 64 | self._data = [None] * (n + 1) 65 | for i in range(n): 66 | self._data[i + 1] = arr[i] 67 | self._count = n 68 | self._capacity = n 69 | for i in range(self._count // 2, 0, -1): 70 | self._shift_down(i) 71 | 72 | def size(self): 73 | return self._count 74 | 75 | def is_empty(self): 76 | return self._count == 0 77 | 78 | def insert(self, item): 79 | assert (self._count + 1) <= self._capacity, 'heap is full' 80 | self._data[self._count + 1] = item 81 | self._count += 1 82 | self._shift_up(self._count) 83 | 84 | def extract_min(self): 85 | assert self._count > 0, 'can not extract_max from empty heap' 86 | ret = self._data[1] 87 | self._data[1], self._data[self._count] = self._data[self._count], self._data[1] 88 | self._count -= 1 89 | self._shift_down(1) 90 | return ret 91 | 92 | def _shift_up(self, index): 93 | # 因为是最小堆,所以父亲节点的值应该要比孩子节点的值要小的 94 | while index > 1 and self._data[index // 2] > self._data[index]: 95 | self._data[index // 2], self._data[index] = self._data[index], self._data[index // 2] 96 | index //= 2 97 | 98 | def _shift_down(self, index): 99 | while 2 * index <= self._count: 100 | j = 2 * index # 在此轮循环中,self._data[index]和self._data[j]交换位置 101 | if j + 1 <= self._count and self._data[j + 1] < self._data[j]: 102 | j += 1 103 | if self._data[index] <= self._data[j]: 104 | break 105 | self._data[index], self._data[j] = self._data[j], self._data[index] 106 | index = j 107 | 108 | 109 | class IndexMaxHeap: 110 | def __init__(self, arr=None, capacity=10): 111 | if not arr: 112 | # for the convenience of indexing 113 | self._data = [None] * (capacity + 1) 114 | self._indexes = [0] * (capacity + 1) 115 | self._reverse = [0] * (capacity + 1) 116 | self._count = 0 117 | self._capacity = capacity 118 | else: 119 | n = len(arr) 120 | self._data = [None] * (n + 1) 121 | self._indexes = [0] * (capacity + 1) 122 | for i in range(n): 123 | self._data[i + 1] = arr[i] 124 | self._count = n 125 | self._capacity = n 126 | for i in range(self._count // 2, 0, -1): 127 | self._shift_down(i) 128 | 129 | def size(self): 130 | return self._count 131 | 132 | def is_empty(self): 133 | return self._count == 0 134 | 135 | # 传入的i对用户而言,是从0索引的 136 | def insert(self, i, item): 137 | assert self._count + 1 <= self._capacity, 'heap is full' 138 | assert i + 1 >= 1 and i + 1 <= self._capacity, 'invalid index' 139 | i += 1 140 | self._data[i] = item 141 | self._indexes[self._count + 1] = i 142 | self._reverse[i] = self._count + 1 143 | self._count += 1 144 | self._shift_up(self._count) 145 | 146 | def extract_max(self): 147 | assert self._count > 0, 'can not extract_max from empty heap' 148 | ret = self._data[self._indexes[1]] 149 | self._swap_indexes(self, 1, self._count) 150 | self._reverse[self._indexes[1]] = 1 151 | self._reverse[self._indexes[self._count]] = 0 152 | self._count -= 1 153 | self._shift_down(1) 154 | return ret 155 | 156 | def extract_max_index(self): 157 | assert self._count > 0, 'can not extract_max from empty heap' 158 | ret_index = self._indexes[1] - 1 159 | self._swap_indexes(self, 1, self._count) 160 | self._reverse[self._indexes[1]] = 1 161 | self._reverse[self._indexes[self._count]] = 0 162 | self._count -= 1 163 | self._shift_down(1) 164 | return ret_index 165 | 166 | def _contains(self, i): 167 | assert i + 1 >= 1 and i + 1 <= self._capacity 168 | return self._reverse[i + 1] != 0 169 | 170 | def get_item(self, i): 171 | assert self._contains(i), 'i is invalid!' 172 | return self._data[i + 1] 173 | 174 | def change(self, i, new_item): 175 | assert self._contains(i), 'i is invalid!' 176 | i += 1 177 | self._data[i] = new_item 178 | # 找到self._indexes[j] = i, j表示self._data[i]在堆中的位置 179 | # 之后self._shift_up(j),再self._shift_down(j) (可以交换顺序) 180 | # for j in range(self._count + 1): 181 | # if self._indexes[j] == i: 182 | # self._shift_up(j) 183 | # self._shift_down(j) 184 | # return 185 | j = self._reverse[i] 186 | self._shift_up(j) 187 | self._shift_down(j) 188 | 189 | def _swap_indexes(self, i, j): 190 | self._indexes[i], self._indexes[j] = self._indexes[j], self._indexes[i] 191 | self._reverse[self._indexes[i]] = i 192 | self._reverse[self._indexes[j]] = j 193 | 194 | def _shift_up(self, index): 195 | # 因为是最大堆,所以父亲节点的值应该要比孩子节点的值要大的 196 | while index > 1 and self._data[self._indexes[index // 2]] < self._data[self._indexes[index]]: 197 | self._data[self._indexes[index // 2]], self._data[self._indexes[index]] = self._data[self._indexes[index]], self._data[self._indexes[index // 2]] 198 | self._reverse[self._indexes[index // 2]] = index // 2 199 | self._reverse[self._indexes[index]] = index 200 | index //= 2 201 | 202 | def _shift_down(self, index): 203 | while 2 * index <= self._count: 204 | j = 2 * index # 在此轮循环中,self._data[self._indexes[index]]和self._data[self._indexes[j]]交换位置 205 | if j + 1 <= self._count and self._data[self._indexes[j + 1]] > self._data[self._indexes[j]]: 206 | j += 1 207 | if self._data[self._indexes[index]] >= self._data[self._indexes[j]]: 208 | break 209 | self._data[self._indexes[index]], self._data[self._indexes[j]] = self._data[self._indexes[j]], self._data[self._indexes[index]] 210 | self._reverse[self._indexes[index]] = index 211 | self._reverse[self._indexes[j]] = j 212 | index = j 213 | 214 | 215 | class IndexMinHeap: 216 | def __init__(self, capacity=10): 217 | # for the convenience of indexing 218 | self._data = [None] * (capacity + 1) 219 | self._indexes = [0] * (capacity + 1) 220 | self._reverse = [0] * (capacity + 1) 221 | self._count = 0 222 | self._capacity = capacity 223 | 224 | def size(self): 225 | return self._count 226 | 227 | def is_empty(self): 228 | return self._count == 0 229 | 230 | # 传入的i对用户而言,是从0索引的 231 | def insert(self, i, item): 232 | assert self._count + 1 <= self._capacity, 'heap is full' 233 | assert i + 1 >= 1 and i + 1 <= self._capacity, 'invalid index' 234 | assert not self._contains(i) 235 | i += 1 236 | self._data[i] = item 237 | self._indexes[self._count + 1] = i 238 | self._reverse[i] = self._count + 1 239 | self._count += 1 240 | self._shift_up(self._count) 241 | 242 | def extract_min(self): 243 | assert self._count > 0, 'can not extract_min from empty heap' 244 | ret = self._data[self._indexes[1]] 245 | self._swap_indexes(1, self._count) 246 | self._reverse[self._indexes[self._count]] = 0 247 | self._count -= 1 248 | self._shift_down(1) 249 | return ret 250 | 251 | def extract_min_index(self): 252 | assert self._count > 0, 'can not extract_max from empty heap' 253 | ret_index = self._indexes[1] - 1 254 | self._swap_indexes(1, self._count) 255 | self._reverse[self._indexes[self._count]] = 0 256 | self._count -= 1 257 | self._shift_down(1) 258 | return ret_index 259 | 260 | def _swap_indexes(self, i, j): 261 | self._indexes[i], self._indexes[j] = self._indexes[j], self._indexes[i] 262 | self._reverse[self._indexes[i]] = i 263 | self._reverse[self._indexes[j]] = j 264 | 265 | def get_min(self): 266 | assert self._count > 0 267 | return self._data[self._indexes[1]] 268 | 269 | def get_min_index(self): 270 | assert self._count > 0 271 | return self._indexes[1] - 1 272 | 273 | def _contains(self, i): 274 | assert i + 1 >= 1 and i + 1 <= self._capacity 275 | return self._reverse[i + 1] != 0 276 | 277 | def get_item(self, i): 278 | assert self._contains(i), 'i is invalid!' 279 | return self._data[i + 1] 280 | 281 | def change(self, i, new_item): 282 | assert self._contains(i), 'i is invalid!' 283 | i += 1 284 | self._data[i] = new_item 285 | # 找到self._indexes[j] = i, j表示self._data[i]在堆中的位置 286 | # 之后self._shift_up(j),再self._shift_down(j) (可以交换顺序) 287 | # for j in range(self._count + 1): 288 | # if self._indexes[j] == i: 289 | # self._shift_up(j) 290 | # self._shift_down(j) 291 | # return 292 | self._shift_up(self._reverse[i]) 293 | self._shift_down(self._reverse[i]) 294 | 295 | def _shift_up(self, k): 296 | # 因为是最小堆,所以父亲节点的值应该要比孩子节点的值要小的 297 | while k > 1 and self._data[self._indexes[k // 2]] > self._data[self._indexes[k]]: 298 | self._swap_indexes(k, k // 2) 299 | k //= 2 300 | 301 | def _shift_down(self, k): 302 | while 2 * k <= self._count: 303 | j = 2 * k # 在此轮循环中,self._data[self._indexes[k]]和self._data[self._indexes[j]]交换位置 304 | if j + 1 <= self._count and self._data[self._indexes[j + 1]] < self._data[self._indexes[j]]: 305 | j += 1 306 | if self._data[self._indexes[k]] <= self._data[self._indexes[j]]: 307 | break 308 | self._swap_indexes(k, j) 309 | k = j 310 | 311 | 312 | def heap_sort1(arr): 313 | n = len(arr) 314 | max_heap = MaxHeap(capacity=n) 315 | for each in arr: 316 | max_heap.insert(each) 317 | for i in range(n - 1, -1, -1): 318 | arr[i] = max_heap.extract_max() 319 | 320 | 321 | def heap_sort2(arr): 322 | max_heap = MaxHeap(arr=arr) 323 | n = len(arr) 324 | for i in range(n - 1, -1, -1): 325 | arr[i] = max_heap.extract_max() 326 | 327 | 328 | def heap_sort(arr): 329 | """原地堆排序""" 330 | n = len(arr) 331 | for i in range((n - 1) // 2, -1, -1): 332 | _shift_down(arr, n, i) 333 | for i in range(n - 1, 0, -1): 334 | arr[0], arr[i] = arr[i], arr[0] 335 | _shift_down(arr, i, 0) 336 | 337 | def _shift_down(arr, n, k): 338 | while 2 * k + 1 < n: 339 | j = 2 * k + 1 340 | if j + 1 < n and arr[j + 1] > arr[j]: 341 | j += 1 342 | if arr[k] >= arr[j]: 343 | break 344 | arr[k], arr[j] = arr[j], arr[k] 345 | k = j 346 | -------------------------------------------------------------------------------- /chapter_04_heap_sort/main.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from chapter_04_heap_sort.heap_sort import MaxHeap 4 | from chapter_04_heap_sort.heap_sort import heap_sort1 5 | from chapter_04_heap_sort.heap_sort import heap_sort2 6 | from chapter_04_heap_sort.heap_sort import heap_sort 7 | from sort_test_helper.helpers import generate_random_array 8 | from sort_test_helper.helpers import generate_nearly_ordered_random_array 9 | from sort_test_helper.helpers import test_sort 10 | from chapter_03_advanced_sort.merge_sort import merge_sort 11 | from chapter_03_advanced_sort.quick_sort import quick_sort 12 | from chapter_03_advanced_sort.quick_sort import quick_sort_3_ways 13 | 14 | 15 | if __name__ == '__main__': 16 | n = 10000 17 | 18 | # test 1 19 | arr1 = generate_random_array(n, 0, n) 20 | test_sort('merge_sort', merge_sort, arr1[:]) 21 | test_sort('quick_sort', quick_sort, arr1[:]) 22 | test_sort('quick_sort_3_ways', quick_sort_3_ways, arr1[:]) 23 | test_sort('heap_sort1', heap_sort1, arr1[:]) 24 | test_sort('heap_sort2', heap_sort2, arr1[:]) 25 | test_sort('heap_sort', heap_sort, arr1[:]) 26 | print('*' * 20) 27 | 28 | # test 2 29 | arr2 = generate_nearly_ordered_random_array(n, 0, n, 0) 30 | test_sort('merge_sort', merge_sort, arr2[:]) 31 | test_sort('quick_sort', quick_sort, arr2[:]) 32 | test_sort('quick_sort_3_ways', quick_sort_3_ways, arr2[:]) 33 | test_sort('heap_sort1', heap_sort1, arr2[:]) 34 | test_sort('heap_sort2', heap_sort2, arr2[:]) 35 | test_sort('heap_sort', heap_sort, arr2[:]) 36 | print('*' * 20) 37 | 38 | # test 3 39 | arr3 = generate_nearly_ordered_random_array(n, 0, n, 500) 40 | test_sort('merge_sort', merge_sort, arr3[:]) 41 | test_sort('quick_sort', quick_sort, arr3[:]) 42 | test_sort('quick_sort_3_ways', quick_sort_3_ways, arr3[:]) 43 | test_sort('heap_sort1', heap_sort1, arr3[:]) 44 | test_sort('heap_sort2', heap_sort2, arr3[:]) 45 | test_sort('heap_sort', heap_sort, arr3[:]) 46 | print('*' * 20) 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /chapter_05_binary_search/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwang96-dl/play-with-algorithms/fa34ae2c17e75b3d233b1426094ce66229090a37/chapter_05_binary_search/__init__.py -------------------------------------------------------------------------------- /chapter_05_binary_search/binary_search.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | 4 | class BST: 5 | class _Node: 6 | def __init__(self, key, value): 7 | self.key = key 8 | self.value = value 9 | self.left = self.right = None 10 | 11 | def __init__(self): 12 | self._root = None 13 | self._count = 0 14 | 15 | def size(self): 16 | return self._count 17 | 18 | def is_empty(self): 19 | return self._count == 0 20 | 21 | def insert(self, key, value): 22 | self._root = self._insert(self._root, key, value) 23 | 24 | def _insert(self, node, key, value): 25 | if not node: 26 | return self._Node(key, value) 27 | if node.key == key: 28 | node.value = value 29 | return node 30 | elif node.key > key: 31 | node.left = self._insert(node.left, key, value) 32 | else: 33 | node.right = self._insert(node.right, key, value) 34 | return node 35 | 36 | def contains(self, key): 37 | return self._contains(self._root, key) 38 | 39 | def _contains(self, node, key): 40 | if not node: 41 | return False 42 | if key == node.key: 43 | return True 44 | elif key < node.key: 45 | return self._contains(node.left, key) 46 | else: 47 | return self._contains(node.right, key) 48 | 49 | def search(self, key): 50 | return self._search(self._root, key) 51 | 52 | def _search(self, node, key): 53 | if not node: 54 | return 55 | if key == node.key: 56 | return node 57 | elif key < node.key: 58 | return self._search(node.left, key) 59 | else: 60 | return self._search(node.right, key) 61 | 62 | def pre_order(self): 63 | self._pre_order(self._root) 64 | 65 | def _pre_order(self, node): 66 | if node: 67 | print(node.key) 68 | self._pre_order(node.left) 69 | self._pre_order(node.right) 70 | 71 | def in_order(self): 72 | self._pre_order(self._root) 73 | 74 | def _in_order(self, node): 75 | if node: 76 | self._in_order(node.left) 77 | print(node.key) 78 | self._in_order(node.right) 79 | 80 | def post_order(self): 81 | self._post_order(self._root) 82 | 83 | def _post_order(self): 84 | if node: 85 | self._post_order(node.left) 86 | self._post_order(node.right) 87 | print(node.key) 88 | 89 | def level_order(self): 90 | queue = deque() 91 | queue.append(self._root) 92 | while queue: 93 | curr = queue.popleft() 94 | print(curr.value) 95 | if curr.left: 96 | queue.append(curr.left) 97 | if curr.right: 98 | queue.append(curr.right) 99 | 100 | def minimum(self): 101 | assert self._count > 0 102 | min_node = self._minimum(self._root) 103 | return min_node.key 104 | 105 | def _minimum(self, node): 106 | if not node.left: 107 | return node 108 | return self._minimum(node.left) 109 | 110 | def maximum(self): 111 | assert self._count > 0 112 | max_node = self._maximum(self._root) 113 | return max_node.key 114 | 115 | def _maximum(self, node): 116 | if not node.right: 117 | return node 118 | return self._maximum(node.right) 119 | 120 | def remove_min(self): 121 | if self._root: 122 | self._root = self._remove_min(self._root) 123 | 124 | def _remove_min(self, node): 125 | if not node.left: 126 | right_node = node.right 127 | self._count -= 1 128 | return right_node 129 | node.left = self._remove_min(node.left) 130 | return node 131 | 132 | def remove_max(self): 133 | if self._root: 134 | self._root = self._remove_max(self._root) 135 | 136 | def _remove_max(self, node): 137 | if not node.right: 138 | left_node = node.left 139 | self._count -= 1 140 | return left_node 141 | node.right = self._remove_max(node.right) 142 | return node 143 | 144 | def remove(self, key): 145 | self._root = self._remove(self._root, key) 146 | 147 | def _remove(self, node, key): 148 | if not node: 149 | return 150 | if key < node.key: 151 | node.left = self._remove(node.left, key) 152 | return node 153 | elif key > node.key: 154 | node.right = self._remove(node.right, key) 155 | return node 156 | else: 157 | if not node.left: 158 | self._count -= 1 159 | return node.right 160 | if not node.right: 161 | self._count -= 1 162 | return node.left 163 | successor = self._minimum(node.right) 164 | successor.right = self._remove_min(node.right) 165 | successor.left = node.left 166 | return successor 167 | 168 | 169 | def binary_search(arr, target): 170 | # 在arr[l...r]之中查找target 171 | # 二分的核心思想是排除不符合条件的那一半 172 | l, r = 0, len(arr) - 1 173 | while l <= r: 174 | mid = l + (r - l) // 2 175 | if arr[mid] == target: 176 | return mid 177 | elif arr[mid] > target: 178 | r = mid - 1 179 | else: 180 | l = mid + 1 181 | return -1 -------------------------------------------------------------------------------- /chapter_05_binary_search/main.py: -------------------------------------------------------------------------------- 1 | from time import time 2 | from chapter_05_binary_search.binary_search import BST 3 | 4 | 5 | if __name__ == '__main__': 6 | with open('./chapter_05_binary_search/shakespeare.txt', 'r') as f: 7 | words = f.read() 8 | words = words.split() 9 | 10 | start_time = time() 11 | bst = BST() 12 | for word in words: 13 | if bst.contains(word): 14 | bst.search(word).value += 1 15 | else: 16 | bst.insert(word, 1) 17 | print('BST time cost: {} seconds'.format(time() - start_time)) 18 | -------------------------------------------------------------------------------- /chapter_06_union_find/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwang96-dl/play-with-algorithms/fa34ae2c17e75b3d233b1426094ce66229090a37/chapter_06_union_find/__init__.py -------------------------------------------------------------------------------- /chapter_06_union_find/main.py: -------------------------------------------------------------------------------- 1 | from sort_test_helper.helpers import union_find_test_helper 2 | from chapter_06_union_find.union_find import UnionFind1 3 | from chapter_06_union_find.union_find import UnionFind2 4 | from chapter_06_union_find.union_find import UnionFind3 5 | from chapter_06_union_find.union_find import UnionFind4 6 | from chapter_06_union_find.union_find import UnionFind5 7 | from chapter_06_union_find.union_find import UnionFind6 8 | 9 | 10 | if __name__ == '__main__': 11 | n = 10000 12 | 13 | # uf1 = UnionFind1(n) 14 | # uf2 = UnionFind2(n) 15 | uf3 = UnionFind3(n) 16 | uf4 = UnionFind4(n) 17 | uf5 = UnionFind5(n) 18 | uf6 = UnionFind6(n) 19 | # union_find_test_helper(uf1, n, 'First Version UF') 20 | # union_find_test_helper(uf2, n, 'Second Version UF') 21 | union_find_test_helper(uf3, n, 'Third Version UF') 22 | union_find_test_helper(uf4, n, 'Fourth Version UF') 23 | union_find_test_helper(uf5, n, 'Fifth Version UF') 24 | union_find_test_helper(uf6, n, 'Sixth Version UF') 25 | -------------------------------------------------------------------------------- /chapter_06_union_find/union_find.py: -------------------------------------------------------------------------------- 1 | class UnionFind1: 2 | def __init__(self, n): 3 | self._count = n 4 | self._id = [i for i in range(n)] 5 | 6 | def _find(self, p): 7 | assert 0 <= p < self._count 8 | return self._id[p] 9 | 10 | def is_connected(self, p, q): 11 | return self._find(p) == self._find(q) 12 | 13 | def union(self, p, q): 14 | assert 0 <= p < self._count and 0 <= q < self._count 15 | p_id = self._find(p) 16 | q_id = self._find(q) 17 | if p_id == q_id: 18 | return 19 | for i in range(self._count): 20 | if self._id[i] == p_id: 21 | self._id[i] = q_id 22 | 23 | 24 | class UnionFind2: 25 | def __init__(self, n): 26 | self._count = n 27 | self._parent = [i for i in range(n)] 28 | 29 | def _find(self, p): 30 | assert 0 <= p < self._count 31 | while p != self._parent[p]: 32 | p = self._parent[p] 33 | # now p is same value as its parent 34 | return p 35 | 36 | def is_connected(self, p, q): 37 | return self._find(p) == self._find(q) 38 | 39 | def union(self, p, q): 40 | assert 0 <= p < self._count and 0 <= q < self._count 41 | p_root = self._find(p) 42 | q_root = self._find(q) 43 | if p_root == q_root: 44 | return 45 | self._parent[p_root] = q_root 46 | 47 | 48 | class UnionFind3: 49 | """基于集合数目的优化""" 50 | def __init__(self, n): 51 | self._count = n 52 | # sz[i]表示以i为根的sz集合中的元素 53 | self._sz = [1] * n 54 | self._parent = [i for i in range(n)] 55 | 56 | def _find(self, p): 57 | assert 0 <= p < self._count 58 | while p != self._parent[p]: 59 | p = self._parent[p] 60 | # now p is same value as its parent 61 | return p 62 | 63 | def is_connected(self, p, q): 64 | return self._find(p) == self._find(q) 65 | 66 | def union(self, p, q): 67 | assert 0 <= p < self._count and 0 <= q < self._count 68 | p_root = self._find(p) 69 | q_root = self._find(q) 70 | if p_root == q_root: 71 | return 72 | if self._sz[p_root] < self._sz[q_root]: 73 | # 小的合并到大的 74 | self._parent[p_root] = q_root 75 | self._sz[q_root] += self._sz[p_root] 76 | else: 77 | self._parent[q_root] = p_root 78 | self._sz[p_root] += self._sz[q_root] 79 | 80 | 81 | class UnionFind4: 82 | """基于rank优化""" 83 | def __init__(self, n): 84 | self._count = n 85 | # rank[i]表示以i为根的集合所表示的树的层数 86 | self._rank = [1] * n 87 | self._parent = [i for i in range(n)] 88 | 89 | def _find(self, p): 90 | assert 0 <= p < self._count 91 | while p != self._parent[p]: 92 | p = self._parent[p] 93 | # now p is same value as its parent 94 | return p 95 | 96 | def is_connected(self, p, q): 97 | return self._find(p) == self._find(q) 98 | 99 | def union(self, p, q): 100 | assert 0 <= p < self._count and 0 <= q < self._count 101 | p_root = self._find(p) 102 | q_root = self._find(q) 103 | if p_root == q_root: 104 | return 105 | if self._rank[p_root] < self._rank[q_root]: 106 | # rank小的合并到大的 107 | self._parent[p_root] = q_root 108 | elif self._rank[p_root] > self._rank[q_root]: 109 | self._parent[q_root] = p_root 110 | else: 111 | self._parent[p_root] = q_root 112 | self._rank[q_root] += 1 113 | 114 | 115 | class UnionFind5: 116 | """路径压缩""" 117 | def __init__(self, n): 118 | self._count = n 119 | # rank[i]表示以i为根的集合所表示的树的层数 120 | self._rank = [1] * n 121 | self._parent = [i for i in range(n)] 122 | 123 | def _find(self, p): 124 | assert 0 <= p < self._count 125 | while p != self._parent[p]: 126 | # 路径压缩 127 | self._parent[p] = self._parent[self._parent[p]] 128 | p = self._parent[p] 129 | # now p is same value as its parent 130 | return p 131 | 132 | def is_connected(self, p, q): 133 | return self._find(p) == self._find(q) 134 | 135 | def union(self, p, q): 136 | assert 0 <= p < self._count and 0 <= q < self._count 137 | p_root = self._find(p) 138 | q_root = self._find(q) 139 | if p_root == q_root: 140 | return 141 | if self._rank[p_root] < self._rank[q_root]: 142 | # rank小的合并到大的 143 | self._parent[p_root] = q_root 144 | elif self._rank[p_root] > self._rank[q_root]: 145 | self._parent[q_root] = p_root 146 | else: 147 | self._parent[p_root] = q_root 148 | self._rank[q_root] += 1 149 | 150 | 151 | class UnionFind6: 152 | """路径压缩,递归优化""" 153 | def __init__(self, n): 154 | self._count = n 155 | # rank[i]表示以i为根的集合所表示的树的层数 156 | self._rank = [1] * n 157 | self._parent = [i for i in range(n)] 158 | 159 | def _find(self, p): 160 | assert 0 <= p < self._count 161 | if p != self._parent[p]: 162 | # 最终指向了最深的父节点 163 | self._parent[p] = self._find(self._parent[p]) 164 | return self._parent[p] 165 | 166 | def is_connected(self, p, q): 167 | return self._find(p) == self._find(q) 168 | 169 | def union(self, p, q): 170 | assert 0 <= p < self._count and 0 <= q < self._count 171 | p_root = self._find(p) 172 | q_root = self._find(q) 173 | if p_root == q_root: 174 | return 175 | if self._rank[p_root] < self._rank[q_root]: 176 | # rank小的合并到大的 177 | self._parent[p_root] = q_root 178 | elif self._rank[p_root] > self._rank[q_root]: 179 | self._parent[q_root] = p_root 180 | else: 181 | self._parent[p_root] = q_root 182 | self._rank[q_root] += 1 183 | -------------------------------------------------------------------------------- /chapter_07_graph/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwang96-dl/play-with-algorithms/fa34ae2c17e75b3d233b1426094ce66229090a37/chapter_07_graph/__init__.py -------------------------------------------------------------------------------- /chapter_07_graph/component.py: -------------------------------------------------------------------------------- 1 | class Component: 2 | """Only for dense graph""" 3 | def __init__(self, graph): 4 | self._graph = graph 5 | self._visited = [False] * graph.V() 6 | self._ccount = 0 7 | self._id = [-1] * graph.V() 8 | for i in range(graph.V()): 9 | if not self._visited[i]: 10 | self._dfs(i) 11 | self._ccount += 1 12 | 13 | def count(self): 14 | return self._ccount 15 | 16 | def _dfs(self, v): 17 | self._visited[v] = True 18 | self._id[v] = self._ccount 19 | for i in self._graph[v]: 20 | if not self._visited[i]: 21 | self._dfs(i) 22 | 23 | def is_connected(self, v, w): 24 | assert 0 <= v < self._graph.V() 25 | assert 0 <= w < self._graph.V() 26 | return self._id[v] == self._id[w] -------------------------------------------------------------------------------- /chapter_07_graph/dense_graph.py: -------------------------------------------------------------------------------- 1 | class DenseGraph: 2 | def __init__(self, n, directed): 3 | # n表示图的节点数 4 | self._n = n 5 | # m表示图的边数 6 | self._m = 0 7 | self._directed = directed 8 | self._g = [[False] * n for _ in range(n)] 9 | 10 | def V(self): 11 | return self._n 12 | 13 | def E(self): 14 | return self._m 15 | 16 | def add_edge(self, v, w): 17 | """顶点v和顶点w连接""" 18 | assert 0 <= v < self._n 19 | assert 0 <= w < self._n 20 | if (self.has_edge(v, w)): 21 | return 22 | self._g[v][w] = True 23 | if not self._directed: 24 | self._g[w][v] = True 25 | self._m += 1 26 | 27 | def has_edge(self, v, w): 28 | assert 0 <= v < self._n 29 | assert 0 <= w < self._n 30 | return self._g[v][w] 31 | 32 | def __iter__(self): 33 | yield from self._g 34 | 35 | def __len__(self): 36 | return self._n 37 | 38 | def __getitem__(self, v): 39 | assert 0 <= v < self._n 40 | return self._g[v] 41 | 42 | def __str__(self): 43 | ret = [':'] 44 | for v in range(len(self._g)): 45 | ret.append('{:2d}: '.format(v) + ' '.join('{:3d}'.format(w) for w in self._g[v])) 46 | return '\n'.join(ret) 47 | 48 | def __repr__(self): 49 | return self.__str__() 50 | 51 | @classmethod 52 | def from_local_file(cls, directed, filename): 53 | with open(filename, 'r') as f: 54 | rows = f.read() 55 | rows = rows.split('\n') 56 | data = [[int(j) for j in each_row_str.split()] for each_row_str in rows] 57 | graph = cls(n=len(data), directed=directed) 58 | for v in range(len(data)): 59 | for w in data[v]: 60 | graph.add_edge(v, w) 61 | return graph -------------------------------------------------------------------------------- /chapter_07_graph/main.py: -------------------------------------------------------------------------------- 1 | from chapter_07_graph.sparse_graph import SparseGraph 2 | from chapter_07_graph.dense_graph import DenseGraph 3 | from chapter_07_graph.component import Component 4 | from chapter_07_graph.path import Path 5 | from chapter_07_graph.shortest_path import ShortestPath 6 | 7 | 8 | if __name__ == '__main__': 9 | # sparse_graph = SparseGraph(n=3, directed=False) 10 | # sparse_graph.add_edge(0, 1) 11 | # sparse_graph.add_edge(0, 2) 12 | 13 | # dense_graph = DenseGraph(n=3, directed=False) 14 | # dense_graph.add_edge(0, 1) 15 | # dense_graph.add_edge(0, 2) 16 | 17 | # for vertex in range(len(sparse_graph)): 18 | # print('Vertex {} -> {}'.format( 19 | # vertex, 20 | # ', '.join(str(i) for i in sparse_graph[vertex]), 21 | # )) 22 | 23 | # for vertex in range(len(dense_graph)): 24 | # print('Vertex {} -> {}'.format( 25 | # vertex, 26 | # ', '.join(str(i) for i in dense_graph[vertex]), 27 | # )) 28 | 29 | # sparse_graph = SparseGraph.from_local_file( 30 | # directed=False, 31 | # filename='./chapter_07_graph/testG.txt', 32 | # ) 33 | # print(sparse_graph) 34 | 35 | # dense_graph = DenseGraph.from_local_file( 36 | # directed=False, 37 | # filename='./chapter_07_graph/testG2.txt', 38 | # ) 39 | # print(dense_graph) 40 | 41 | # sparse_graph = SparseGraph.from_local_file( 42 | # directed=False, 43 | # filename='./chapter_07_graph/testG1.txt', 44 | # ) 45 | # component = Component(sparse_graph) 46 | # print(component.count()) 47 | 48 | # sparse_graph1 = SparseGraph.from_local_file( 49 | # directed=False, 50 | # filename='./chapter_07_graph/testG1.txt', 51 | # ) 52 | # component1 = Component(sparse_graph1) 53 | # print(component1.count()) 54 | 55 | # sparse_graph2 = SparseGraph.from_local_file( 56 | # directed=False, 57 | # filename='./chapter_07_graph/testG2.txt', 58 | # ) 59 | # component2 = Component(sparse_graph2) 60 | # print(component2.count()) 61 | 62 | # sparse_graph = SparseGraph(n=4, directed=False) 63 | # sparse_graph.add_edge(0, 1) 64 | # sparse_graph.add_edge(0, 2) 65 | # sparse_graph.add_edge(1, 2) 66 | # component = Component(sparse_graph) 67 | # print(component.count()) 68 | 69 | sparse_graph = SparseGraph.from_local_file( 70 | directed=False, 71 | filename='./chapter_07_graph/testG2.txt', 72 | ) 73 | path = Path(sparse_graph, 0) 74 | print('DFS: ') 75 | path.show_path(6) 76 | 77 | sparse_graph_bfs = SparseGraph.from_local_file( 78 | directed=False, 79 | filename='./chapter_07_graph/testG2.txt', 80 | ) 81 | shortest_path = ShortestPath(sparse_graph_bfs, 0) 82 | print('BFS: ') 83 | shortest_path.show_path(6) -------------------------------------------------------------------------------- /chapter_07_graph/path.py: -------------------------------------------------------------------------------- 1 | class Path: 2 | def __init__(self, graph, s): 3 | self._G = graph 4 | assert 0 <= s < self._G.V() 5 | # s是从哪里起步 6 | self._s = s 7 | self._from = [-1] * self._G.V() 8 | self._visited = [False] * self._G.V() 9 | self._dfs(s) 10 | 11 | def has_path(self, w): 12 | """从s到w有没有路径""" 13 | assert 0 <= w < self._G.V() 14 | return self._visited[w] 15 | 16 | def path(self, w): 17 | """从s到w点的路径""" 18 | assert 0 <= w < self._G.V() 19 | s = [] 20 | p = w 21 | while p != -1: 22 | s.append(p) 23 | p = self._from[p] 24 | return s 25 | 26 | def show_path(self, w): 27 | """打印从s到w点的路径""" 28 | vec = self.path(w) 29 | print('start ' + ' -> '.join(str(i) for i in vec[::-1]) + ' end') 30 | 31 | def _dfs(self, v): 32 | self._visited[v] = True 33 | for i in self._G[v]: 34 | if not self._visited[i]: 35 | self._from[i] = v 36 | self._dfs(i) 37 | -------------------------------------------------------------------------------- /chapter_07_graph/shortest_path.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | 4 | class ShortestPath: 5 | def __init__(self, graph, s): 6 | self._G = graph 7 | assert 0 <= s < self._G.V() 8 | # s是从哪里起步 9 | self._s = s 10 | self._from = [-1] * self._G.V() 11 | self._visited = [False] * self._G.V() 12 | # order数组记录从s到每一个点的距离 13 | self._ord = [-1] * self._G.V() 14 | self._bfs() 15 | 16 | def has_path(self, w): 17 | """从s到w有没有路径""" 18 | assert 0 <= w < self._G.V() 19 | return self._visited[w] 20 | 21 | def path(self, w): 22 | """从s到w点的路径""" 23 | assert 0 <= w < self._G.V() 24 | s = [] 25 | p = w 26 | while p != -1: 27 | s.append(p) 28 | p = self._from[p] 29 | return s 30 | 31 | def show_path(self, w): 32 | """打印从s到w点的路径""" 33 | vec = self.path(w) 34 | print('start ' + ' -> '.join(str(i) for i in vec[::-1]) + ' end') 35 | 36 | def length(self, w): 37 | assert 0 <= w < self._G.V() 38 | return self._ord[w] 39 | 40 | def _bfs(self): 41 | queue = deque() 42 | queue.append(self._s) 43 | self._visited[self._s] = True 44 | while queue: 45 | curr = queue.popleft() 46 | for i in self._G[curr]: 47 | if not self._visited[i]: 48 | queue.append(i) 49 | self._visited[i] = True 50 | self._from[i] = curr 51 | self._ord[i] = self._ord[curr] + 1 52 | -------------------------------------------------------------------------------- /chapter_07_graph/sparse_graph.py: -------------------------------------------------------------------------------- 1 | class SparseGraph: 2 | def __init__(self, n, directed): 3 | self._n = n 4 | self._m = 0 5 | self._directed = directed 6 | self._g = [[] for _ in range(n)] 7 | 8 | def V(self): 9 | return self._n 10 | 11 | def E(self): 12 | return self._m 13 | 14 | def add_edge(self, v, w): 15 | assert 0 <= v < self._n 16 | assert 0 <= w < self._n 17 | if (self.has_edge(v, w)): 18 | return 19 | self._g[v].append(w) 20 | if v != w and not self._directed: 21 | self._g[w].append(v) 22 | self._m += 1 23 | 24 | def has_edge(self, v, w): 25 | assert 0 <= v < self._n 26 | assert 0 <= w < self._n 27 | for i in range(len(self._g[v])): 28 | if self._g[v][i] == w: 29 | return True 30 | return False 31 | 32 | def __iter__(self): 33 | yield from self._g 34 | 35 | def __len__(self): 36 | return self._n 37 | 38 | def __getitem__(self, v): 39 | assert 0 <= v < self._n 40 | return self._g[v] 41 | 42 | def __str__(self): 43 | ret = [':'] 44 | for v in range(len(self._g)): 45 | ret.append('{:2d}: '.format(v) + ' '.join('{:3d}'.format(w) for w in self._g[v])) 46 | return '\n'.join(ret) 47 | 48 | def __repr__(self): 49 | return self.__str__() 50 | 51 | @classmethod 52 | def from_local_file(cls, directed, filename): 53 | with open(filename, 'r') as f: 54 | rows = f.read() 55 | rows = rows.split('\n') 56 | data = [[int(j) for j in each_row_str.split()] for each_row_str in rows] 57 | graph = cls(n=len(data), directed=directed) 58 | for v in range(len(data)): 59 | for w in data[v]: 60 | graph.add_edge(v, w) 61 | return graph -------------------------------------------------------------------------------- /chapter_07_graph/testG.txt: -------------------------------------------------------------------------------- 1 | 7 8 2 | 0 1 3 | 0 2 4 | 0 5 5 | 0 6 6 | 3 4 7 | 3 5 8 | 4 5 9 | 4 6 -------------------------------------------------------------------------------- /chapter_07_graph/testG1.txt: -------------------------------------------------------------------------------- 1 | 0 5 2 | 4 3 3 | 0 1 4 | 9 12 5 | 6 4 6 | 5 4 7 | 0 2 8 | 11 12 9 | 9 10 10 | 0 6 11 | 7 8 12 | 9 11 13 | 5 3 -------------------------------------------------------------------------------- /chapter_07_graph/testG2.txt: -------------------------------------------------------------------------------- 1 | 1 2 5 6 2 | 0 3 | 0 4 | 4 5 5 | 3 5 6 6 | 0 3 4 7 | 0 4 -------------------------------------------------------------------------------- /chapter_08_minimum_span_tree/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwang96-dl/play-with-algorithms/fa34ae2c17e75b3d233b1426094ce66229090a37/chapter_08_minimum_span_tree/__init__.py -------------------------------------------------------------------------------- /chapter_08_minimum_span_tree/dense_graph.py: -------------------------------------------------------------------------------- 1 | from chapter_08_minimum_span_tree.edge import Edge 2 | 3 | 4 | class DenseGraph: 5 | def __init__(self, n, directed): 6 | # n表示图的节点数 7 | self._n = n 8 | # m表示图的边数 9 | self._m = 0 10 | self._directed = directed 11 | self._g = [[None] * n for _ in range(n)] 12 | 13 | def V(self): 14 | return self._n 15 | 16 | def E(self): 17 | return self._m 18 | 19 | def add_edge(self, v, w, weight): 20 | """顶点v和顶点w连接""" 21 | assert 0 <= v < self._n 22 | assert 0 <= w < self._n 23 | if not self.has_edge(v, w): 24 | self._m += 1 25 | self._g[v][w] = Edge(v, w, weight) 26 | if not self._directed: 27 | self._g[w][v] = Edge(w, v, weight) 28 | 29 | 30 | def has_edge(self, v, w): 31 | assert 0 <= v < self._n 32 | assert 0 <= w < self._n 33 | return self._g[v][w] != None 34 | 35 | def __iter__(self): 36 | """`i for i in dense_graph_obj`""" 37 | yield from self._g 38 | 39 | def __len__(self): 40 | return self._n 41 | 42 | def __getitem__(self, v): 43 | assert 0 <= v < self._n 44 | return self._g[v] 45 | 46 | def __str__(self): 47 | ret = [':'] 48 | header_gutter = 8 49 | header = ''.rjust(header_gutter) + ''.join(str(i).rjust(header_gutter) for i in range(len(self._g))) 50 | ret.append(header) 51 | for v in range(len(self._g)): 52 | temp = '' 53 | for each_edge in self._g[v]: 54 | if each_edge is None: 55 | temp += ''.rjust(8) 56 | else: 57 | temp += ' {:1.4f}'.format(each_edge.wt()).rjust(8) 58 | ret.append('vertex {}: '.format(v) + temp) 59 | return '\n'.join(ret) 60 | 61 | def __repr__(self): 62 | return self.__str__() 63 | 64 | @classmethod 65 | def from_local_file(cls, directed, filename): 66 | with open(filename, 'r') as f: 67 | rows = f.read() 68 | rows = rows.split('\n') 69 | data = [each_row_str.split() for each_row_str in rows] 70 | n, _ = data[0] 71 | n = int(n) 72 | data = data[1:] 73 | graph = cls(n=n, directed=directed) 74 | for each_row in data: 75 | from_edge, end_edge, weight = each_row 76 | graph.add_edge(int(from_edge), int(end_edge), float(weight)) 77 | return graph -------------------------------------------------------------------------------- /chapter_08_minimum_span_tree/edge.py: -------------------------------------------------------------------------------- 1 | class Edge: 2 | def __init__(self, a=None, b=None, weight=None): 3 | # 从a指向b 4 | self._a = a 5 | self._b = b 6 | self._weight = weight 7 | 8 | def v(self): 9 | return self._a 10 | 11 | def w(self): 12 | return self._b 13 | 14 | def wt(self): 15 | return self._weight 16 | 17 | def other(self, x): 18 | assert x == self._a or x == self._b 19 | return self._b if x == self._a else self._a 20 | 21 | def __str__(self): 22 | return '{} -> {}'.format(self._a, self._b) 23 | 24 | def __repr__(self): 25 | return self.__str__() 26 | 27 | def __lt__(self, other_edge): 28 | assert isinstance(other_edge, Edge), 'can not other type with object' 29 | return self._weight < other_edge.wt() 30 | 31 | def __le__(self, other_edge): 32 | assert isinstance(other_edge, Edge), 'can not other type with object' 33 | return self._weight <= other_edge.wt() 34 | 35 | def __gt__(self, other_edge): 36 | assert isinstance(other_edge, Edge), 'can not other type with object' 37 | return self._weight > other_edge.wt() 38 | 39 | def __ge__(self, other_edge): 40 | assert isinstance(other_edge, Edge), 'can not other type with object' 41 | return self._weight >= other_edge.wt() 42 | 43 | 44 | -------------------------------------------------------------------------------- /chapter_08_minimum_span_tree/kruskal_mst.py: -------------------------------------------------------------------------------- 1 | from chapter_06_union_find.union_find import UnionFind6 as UnionFind 2 | from chapter_04_heap_sort.heap_sort import MinHeap 3 | 4 | 5 | class KruskalMST: 6 | def __init__(self, graph): 7 | self._mst = [] 8 | pq = MinHeap(capacity=graph.E()) 9 | for i in range(graph.V()): 10 | for e in graph[i]: 11 | if e.v() <= e.w(): 12 | pq.insert(e) 13 | uf = UnionFind(graph.V()) 14 | while not pq.is_empty() and len(self._mst) < graph.V() - 1: 15 | e = pq.extract_min() 16 | if uf.is_connected(e.v(), e.w()): 17 | continue 18 | self._mst.append(e) 19 | uf.union(e.v(), e.w()) 20 | self._mst_weight = self._mst[0].wt() 21 | for each in self._mst[1:]: 22 | self._mst_weight += each.wt() 23 | 24 | def mst_edges(self): 25 | return self._mst 26 | 27 | def result(self): 28 | return self._mst_weight -------------------------------------------------------------------------------- /chapter_08_minimum_span_tree/lazy_prim_heap.py: -------------------------------------------------------------------------------- 1 | from chapter_04_heap_sort.heap_sort import IndexMinHeap 2 | 3 | 4 | class PrimMST: 5 | def __init__(self, graph): 6 | self._G = graph 7 | assert self._G.E() >= 1 8 | self._ipq = IndexMinHeap(capacity=graph.V()) 9 | self._marked = [False] * self._G.V() 10 | self._edge_to = [None] * self._G.V() 11 | self._mst = [] 12 | self._visit(0) 13 | while not self._ipq.is_empty(): 14 | v = self._ipq.extract_min_index() 15 | assert self._edge_to[v] is not None 16 | self._mst.append(self._edge_to[v]) 17 | self._visit(v) 18 | self._mst_weight = self._mst[0].wt() 19 | for each in self._mst[1:]: 20 | self._mst_weight += each.wt() 21 | 22 | def _visit(self, v): 23 | assert not self._marked[v] 24 | self._marked[v] = True 25 | for e in self._G[v]: 26 | w = e.other(v) 27 | if not self._marked[w]: 28 | if not self._edge_to[w]: 29 | self._edge_to[w] = e 30 | self._ipq.insert(w, e.wt()) 31 | elif e.wt() < self._edge_to[w].wt(): 32 | self._edge_to[w] = e 33 | self._ipq.change(w, e.wt()) 34 | 35 | def mst_edges(self): 36 | return self._mst 37 | 38 | def result(self): 39 | return self._mst_weight -------------------------------------------------------------------------------- /chapter_08_minimum_span_tree/lazy_prim_mst.py: -------------------------------------------------------------------------------- 1 | from heapq import heappush 2 | from heapq import heappop 3 | 4 | 5 | class LazyPrimMST: 6 | def __init__(self, graph): 7 | self._G = graph 8 | self._pq = [] 9 | self._marked = [False] * self._G.V() 10 | self._mst = [] 11 | self._mst_weight = None 12 | self._visit(0) 13 | while self._pq: 14 | e = heappop(self._pq) 15 | if self._marked[e.v()] == self._marked[e.w()]: 16 | continue 17 | self._mst.append(e) 18 | if not self._marked[e.v()]: 19 | self._visit(e.v()) 20 | else: 21 | self._visit(e.w()) 22 | self._mst_weight = self._mst[0].wt() 23 | for each in self._mst[1:]: 24 | self._mst_weight += each.wt() 25 | 26 | def mst_edges(self): 27 | return self._mst 28 | 29 | def result(self): 30 | return self._mst_weight 31 | 32 | def _visit(self, v): 33 | assert not self._marked[v] 34 | self._marked[v] = True 35 | for e in self._G[v]: 36 | if not self._marked[e.other(v)]: 37 | heappush(self._pq, e) -------------------------------------------------------------------------------- /chapter_08_minimum_span_tree/main.py: -------------------------------------------------------------------------------- 1 | from chapter_08_minimum_span_tree.dense_graph import DenseGraph 2 | from chapter_08_minimum_span_tree.sparse_graph import SparseGraph 3 | from chapter_08_minimum_span_tree.lazy_prim_mst import LazyPrimMST 4 | from chapter_08_minimum_span_tree.lazy_prim_heap import PrimMST 5 | from chapter_08_minimum_span_tree.kruskal_mst import KruskalMST 6 | 7 | 8 | 9 | if __name__ == '__main__': 10 | # dense_graph = DenseGraph.from_local_file( 11 | # directed=True, 12 | # filename='./chapter_08_minimum_span_tree/testG1.txt', 13 | # ) 14 | # print(dense_graph) 15 | 16 | # sparse_graph = SparseGraph.from_local_file( 17 | # directed=True, 18 | # filename='./chapter_08_minimum_span_tree/testG3.txt', 19 | # ) 20 | # print(sparse_graph) 21 | 22 | sparse_graph = SparseGraph.from_local_file( 23 | directed=False, 24 | filename='./chapter_08_minimum_span_tree/testG1.txt', 25 | ) 26 | 27 | lazy_prime_mst = LazyPrimMST(sparse_graph) 28 | print('lazy_prime_mst Edges: ', lazy_prime_mst.mst_edges()) 29 | print('lazy_prime_mst Minium weight sum: ', lazy_prime_mst.result()) 30 | 31 | prime_mst = PrimMST(sparse_graph) 32 | print('prime_mst Edges: ', prime_mst.mst_edges()) 33 | print('prime_mst Minium weight sum: ', prime_mst.result()) 34 | 35 | kruskal_mst = KruskalMST(sparse_graph) 36 | print('kruskal_mst Edges: ', kruskal_mst.mst_edges()) 37 | print('kruskal_mst Minium weight sum: ', kruskal_mst.result()) -------------------------------------------------------------------------------- /chapter_08_minimum_span_tree/sparse_graph.py: -------------------------------------------------------------------------------- 1 | from chapter_08_minimum_span_tree.edge import Edge 2 | 3 | 4 | class SparseGraph: 5 | def __init__(self, n, directed): 6 | self._n = n 7 | self._m = 0 8 | self._directed = directed 9 | self._g = [[] for _ in range(n)] 10 | 11 | def V(self): 12 | return self._n 13 | 14 | def E(self): 15 | return self._m 16 | 17 | def add_edge(self, v, w, weight): 18 | assert 0 <= v < self._n 19 | assert 0 <= w < self._n 20 | self._g[v].append(Edge(v, w, weight)) 21 | if v != w and not self._directed: 22 | self._g[w].append(Edge(w, v, weight)) 23 | self._m += 1 24 | 25 | def has_edge(self, v, w): 26 | assert 0 <= v < self._n 27 | assert 0 <= w < self._n 28 | for i in range(len(self._g[v])): 29 | if self._g[v][i].other(v) == w: 30 | return True 31 | return False 32 | 33 | def __iter__(self): 34 | """`i for i in sparse_graph_obj`""" 35 | yield from self._g 36 | 37 | def __len__(self): 38 | return self._n 39 | 40 | def __getitem__(self, v): 41 | assert 0 <= v < self._n 42 | return self._g[v] 43 | 44 | def __str__(self): 45 | ret = [':'] 46 | for v in range(len(self._g)): 47 | temp = [] 48 | for each_edge in self._g[v]: 49 | temp.append(' to {} with weight {:1.4f}'.format(each_edge.w(), each_edge.wt()).rjust(8)) 50 | ret.append('vertex {}: '.format(v).rjust(4) + ', '.join(temp)) 51 | return '\n'.join(ret) 52 | 53 | def __repr__(self): 54 | return self.__str__() 55 | 56 | @classmethod 57 | def from_local_file(cls, directed, filename): 58 | with open(filename, 'r') as f: 59 | rows = f.read() 60 | rows = rows.split('\n') 61 | data = [each_row_str.split() for each_row_str in rows] 62 | n, _ = data[0] 63 | n = int(n) 64 | data = data[1:] 65 | graph = cls(n=n, directed=directed) 66 | for each_row in data: 67 | from_edge, end_edge, weight = each_row 68 | graph.add_edge(int(from_edge), int(end_edge), float(weight)) 69 | return graph -------------------------------------------------------------------------------- /chapter_08_minimum_span_tree/testG1.txt: -------------------------------------------------------------------------------- 1 | 8 16 2 | 4 5 .35 3 | 4 7 .37 4 | 5 7 .28 5 | 0 7 .16 6 | 1 5 .32 7 | 0 4 .38 8 | 2 3 .17 9 | 1 7 .19 10 | 0 2 .26 11 | 1 2 .36 12 | 1 3 .29 13 | 2 7 .34 14 | 6 2 .40 15 | 3 6 .52 16 | 6 0 .58 17 | 6 4 .93 -------------------------------------------------------------------------------- /chapter_08_minimum_span_tree/testG2.txt: -------------------------------------------------------------------------------- 1 | 250 1273 2 | 244 246 0.11712 3 | 239 240 0.10616 4 | 238 245 0.06142 5 | 235 238 0.07048 6 | 233 240 0.07634 7 | 232 248 0.10223 8 | 231 248 0.10699 9 | 229 249 0.10098 10 | 228 241 0.01473 11 | 226 231 0.07638 12 | 223 242 0.10184 13 | 223 249 0.10898 14 | 222 225 0.09842 15 | 220 247 0.10309 16 | 219 221 0.06535 17 | 218 224 0.05993 18 | 218 227 0.09192 19 | 217 232 0.09613 20 | 216 232 0.08738 21 | 214 219 0.04104 22 | 214 221 0.10444 23 | 213 235 0.09305 24 | 213 238 0.10707 25 | 212 214 0.09024 26 | 212 219 0.08099 27 | 212 221 0.08320 28 | 212 244 0.04321 29 | 211 222 0.06192 30 | 211 225 0.10649 31 | 210 212 0.05813 32 | 210 214 0.07099 33 | 210 219 0.03728 34 | 210 221 0.03659 35 | 210 244 0.10062 36 | 209 211 0.01269 37 | 209 222 0.07357 38 | 209 225 0.11652 39 | 208 226 0.04662 40 | 208 231 0.08821 41 | 207 210 0.03158 42 | 207 212 0.05667 43 | 207 214 0.10119 44 | 207 219 0.06878 45 | 207 221 0.02902 46 | 207 244 0.09218 47 | 206 209 0.11467 48 | 205 207 0.10606 49 | 205 210 0.07932 50 | 205 214 0.07345 51 | 205 219 0.05157 52 | 205 221 0.08879 53 | 204 222 0.09626 54 | 204 225 0.05003 55 | 204 231 0.11432 56 | 203 249 0.04148 57 | 202 204 0.04207 58 | 202 209 0.10956 59 | 202 211 0.09692 60 | 202 222 0.05440 61 | 202 225 0.06056 62 | 201 216 0.11363 63 | 201 217 0.11118 64 | 201 232 0.03557 65 | 201 248 0.06668 66 | 200 203 0.05651 67 | 200 223 0.09984 68 | 200 249 0.06335 69 | 199 237 0.06767 70 | 198 223 0.09036 71 | 198 242 0.03037 72 | 197 230 0.09937 73 | 196 205 0.05718 74 | 196 214 0.08233 75 | 196 219 0.08903 76 | 195 238 0.11390 77 | 195 245 0.09286 78 | 194 220 0.11551 79 | 193 243 0.09306 80 | 192 243 0.07897 81 | 191 202 0.06216 82 | 191 204 0.07061 83 | 191 222 0.09234 84 | 191 225 0.11446 85 | 191 231 0.11935 86 | 190 220 0.04330 87 | 190 247 0.06680 88 | 189 200 0.11303 89 | 189 203 0.05779 90 | 189 220 0.09403 91 | 189 249 0.08557 92 | 188 230 0.05191 93 | 188 233 0.08575 94 | 188 240 0.09560 95 | 187 208 0.06557 96 | 187 226 0.03660 97 | 187 231 0.04215 98 | 187 248 0.11716 99 | 186 189 0.05775 100 | 186 203 0.10305 101 | 186 249 0.11195 102 | 185 201 0.06956 103 | 185 232 0.10259 104 | 185 248 0.02896 105 | 184 188 0.07566 106 | 184 197 0.05351 107 | 184 230 0.04691 108 | 183 215 0.03017 109 | 182 198 0.07870 110 | 182 223 0.08452 111 | 182 242 0.10811 112 | 181 184 0.08764 113 | 181 188 0.10778 114 | 181 196 0.11674 115 | 181 230 0.05963 116 | 180 213 0.03355 117 | 179 193 0.10256 118 | 179 212 0.09146 119 | 179 244 0.07050 120 | 178 236 0.02867 121 | 177 186 0.03537 122 | 177 189 0.03512 123 | 177 203 0.06820 124 | 177 249 0.07806 125 | 176 191 0.02089 126 | 176 202 0.04299 127 | 176 204 0.06123 128 | 176 222 0.07243 129 | 176 225 0.09939 130 | 175 246 0.03569 131 | 174 179 0.09292 132 | 174 192 0.07813 133 | 174 243 0.07415 134 | 172 180 0.08119 135 | 172 197 0.09121 136 | 172 213 0.05932 137 | 172 235 0.07388 138 | 171 172 0.06889 139 | 171 180 0.10106 140 | 171 213 0.06758 141 | 171 235 0.03106 142 | 171 238 0.05664 143 | 171 245 0.11526 144 | 170 182 0.06422 145 | 170 198 0.10237 146 | 170 223 0.03653 147 | 170 229 0.10924 148 | 170 249 0.11264 149 | 169 177 0.08571 150 | 169 186 0.05624 151 | 169 189 0.08899 152 | 169 190 0.09320 153 | 169 220 0.10104 154 | 168 187 0.04080 155 | 168 204 0.11515 156 | 168 208 0.08885 157 | 168 226 0.07555 158 | 168 231 0.00268 159 | 168 248 0.10481 160 | 167 224 0.07521 161 | 166 236 0.09479 162 | 165 171 0.11685 163 | 165 172 0.09828 164 | 165 180 0.01756 165 | 165 191 0.10673 166 | 165 213 0.05003 167 | 164 190 0.07043 168 | 164 194 0.07229 169 | 164 220 0.05001 170 | 164 247 0.09969 171 | 163 202 0.09825 172 | 163 209 0.02235 173 | 163 211 0.01708 174 | 163 222 0.05489 175 | 163 225 0.11682 176 | 162 192 0.09472 177 | 161 169 0.10571 178 | 161 177 0.07299 179 | 161 186 0.06124 180 | 161 189 0.10748 181 | 161 229 0.10509 182 | 161 249 0.11843 183 | 160 168 0.06839 184 | 160 176 0.06571 185 | 160 187 0.10794 186 | 160 191 0.05410 187 | 160 202 0.08639 188 | 160 204 0.06352 189 | 160 225 0.11314 190 | 160 231 0.06647 191 | 159 234 0.05490 192 | 159 239 0.10493 193 | 158 170 0.05722 194 | 158 200 0.07196 195 | 158 203 0.09121 196 | 158 223 0.05291 197 | 158 229 0.09925 198 | 158 249 0.05734 199 | 157 181 0.05473 200 | 157 184 0.04716 201 | 157 188 0.10501 202 | 157 197 0.07152 203 | 157 230 0.05597 204 | 156 196 0.08377 205 | 156 205 0.05088 206 | 156 207 0.07567 207 | 156 210 0.04409 208 | 156 212 0.08418 209 | 156 214 0.03435 210 | 156 219 0.00745 211 | 156 221 0.07280 212 | 155 165 0.05001 213 | 155 171 0.07487 214 | 155 172 0.04996 215 | 155 180 0.03246 216 | 155 197 0.11679 217 | 155 213 0.01559 218 | 155 235 0.09681 219 | 155 238 0.11940 220 | 154 171 0.08024 221 | 154 195 0.11016 222 | 154 235 0.09296 223 | 154 238 0.02365 224 | 154 245 0.04011 225 | 153 228 0.05583 226 | 153 241 0.04247 227 | 152 179 0.10233 228 | 152 207 0.08799 229 | 152 210 0.10636 230 | 152 212 0.05852 231 | 152 221 0.11655 232 | 152 244 0.03365 233 | 152 246 0.09510 234 | 151 168 0.09264 235 | 151 187 0.06861 236 | 151 208 0.00391 237 | 151 226 0.04792 238 | 151 231 0.09202 239 | 150 164 0.09115 240 | 150 169 0.06638 241 | 150 177 0.08428 242 | 150 186 0.08087 243 | 150 189 0.06046 244 | 150 190 0.06182 245 | 150 203 0.11351 246 | 150 220 0.04158 247 | 149 163 0.07447 248 | 149 206 0.10265 249 | 149 209 0.05363 250 | 149 211 0.05830 251 | 149 222 0.11405 252 | 149 225 0.10995 253 | 148 157 0.01712 254 | 148 181 0.05620 255 | 148 184 0.03398 256 | 148 188 0.08809 257 | 148 197 0.07085 258 | 148 230 0.04043 259 | 147 162 0.09416 260 | 147 166 0.11877 261 | 146 218 0.06252 262 | 146 224 0.11387 263 | 146 227 0.04560 264 | 145 146 0.10595 265 | 144 168 0.09650 266 | 144 185 0.03018 267 | 144 187 0.11380 268 | 144 201 0.08140 269 | 144 204 0.11540 270 | 144 231 0.09846 271 | 144 232 0.11686 272 | 144 248 0.01527 273 | 143 152 0.07831 274 | 143 175 0.10421 275 | 143 179 0.08905 276 | 143 193 0.06865 277 | 143 212 0.11875 278 | 143 244 0.07554 279 | 143 246 0.07590 280 | 142 154 0.11701 281 | 142 155 0.04818 282 | 142 165 0.04797 283 | 142 171 0.08119 284 | 142 172 0.09299 285 | 142 180 0.04124 286 | 142 195 0.08901 287 | 142 213 0.03433 288 | 142 235 0.11123 289 | 142 238 0.10237 290 | 140 147 0.04712 291 | 140 162 0.10969 292 | 139 156 0.06665 293 | 139 196 0.04593 294 | 139 205 0.01814 295 | 139 210 0.09743 296 | 139 214 0.08428 297 | 139 219 0.06833 298 | 139 221 0.10596 299 | 138 151 0.11903 300 | 138 188 0.10136 301 | 138 226 0.11064 302 | 138 233 0.09598 303 | 138 239 0.11352 304 | 138 240 0.02076 305 | 137 145 0.11708 306 | 137 146 0.03524 307 | 137 183 0.11008 308 | 137 215 0.11222 309 | 137 218 0.04325 310 | 137 224 0.10278 311 | 137 227 0.07930 312 | 136 159 0.02310 313 | 136 234 0.03185 314 | 135 141 0.06693 315 | 135 181 0.07362 316 | 135 230 0.11174 317 | 134 137 0.10296 318 | 134 145 0.10314 319 | 134 146 0.06821 320 | 134 227 0.03986 321 | 133 166 0.06778 322 | 132 154 0.08146 323 | 132 171 0.07460 324 | 132 235 0.05508 325 | 132 238 0.06935 326 | 131 143 0.05854 327 | 131 179 0.09728 328 | 131 193 0.01012 329 | 131 243 0.10112 330 | 130 194 0.05825 331 | 130 234 0.11697 332 | 129 133 0.07141 333 | 129 147 0.08531 334 | 129 166 0.03392 335 | 129 178 0.11909 336 | 129 236 0.09707 337 | 128 136 0.11358 338 | 128 159 0.09153 339 | 128 173 0.11948 340 | 128 239 0.01726 341 | 126 183 0.08912 342 | 126 215 0.05899 343 | 125 148 0.04208 344 | 125 157 0.02917 345 | 125 172 0.11220 346 | 125 181 0.08041 347 | 125 184 0.05816 348 | 125 197 0.05633 349 | 125 230 0.08248 350 | 124 142 0.06118 351 | 124 155 0.01487 352 | 124 165 0.05177 353 | 124 171 0.08584 354 | 124 172 0.04713 355 | 124 180 0.03552 356 | 124 197 0.10321 357 | 124 213 0.03033 358 | 124 235 0.10482 359 | 123 175 0.07983 360 | 123 246 0.10306 361 | 122 139 0.01217 362 | 122 156 0.05505 363 | 122 196 0.05144 364 | 122 205 0.00647 365 | 122 207 0.11241 366 | 122 210 0.08536 367 | 122 214 0.07516 368 | 122 219 0.05638 369 | 122 221 0.09525 370 | 121 158 0.08749 371 | 121 170 0.03464 372 | 121 182 0.03939 373 | 121 198 0.07031 374 | 121 223 0.04530 375 | 121 242 0.09371 376 | 120 145 0.09428 377 | 120 161 0.09789 378 | 120 229 0.08292 379 | 119 120 0.10342 380 | 119 134 0.04953 381 | 119 137 0.09676 382 | 119 145 0.05361 383 | 119 146 0.07143 384 | 119 227 0.07465 385 | 118 124 0.06300 386 | 118 142 0.11650 387 | 118 151 0.10687 388 | 118 155 0.07746 389 | 118 165 0.08159 390 | 118 172 0.08663 391 | 118 180 0.07699 392 | 118 184 0.11388 393 | 118 197 0.06902 394 | 118 208 0.10634 395 | 118 213 0.09204 396 | 117 140 0.10873 397 | 117 147 0.11794 398 | 117 167 0.09427 399 | 117 178 0.06290 400 | 117 236 0.08473 401 | 116 164 0.04060 402 | 116 190 0.07925 403 | 116 194 0.08583 404 | 116 220 0.08021 405 | 116 247 0.07638 406 | 115 153 0.05126 407 | 115 228 0.08124 408 | 115 241 0.06730 409 | 114 163 0.05526 410 | 114 176 0.08339 411 | 114 191 0.10158 412 | 114 202 0.07319 413 | 114 204 0.11526 414 | 114 209 0.07685 415 | 114 211 0.06713 416 | 114 222 0.02060 417 | 114 225 0.11896 418 | 113 121 0.05379 419 | 113 158 0.09842 420 | 113 170 0.07229 421 | 113 182 0.08536 422 | 113 198 0.05009 423 | 113 223 0.04665 424 | 113 242 0.05551 425 | 112 128 0.09960 426 | 112 136 0.05632 427 | 112 159 0.04347 428 | 112 234 0.08047 429 | 112 239 0.10722 430 | 110 122 0.05351 431 | 110 139 0.06016 432 | 110 156 0.03963 433 | 110 196 0.05323 434 | 110 205 0.05391 435 | 110 207 0.11522 436 | 110 210 0.08364 437 | 110 212 0.11550 438 | 110 214 0.02920 439 | 110 219 0.04680 440 | 110 221 0.11114 441 | 109 126 0.09332 442 | 109 137 0.05083 443 | 109 146 0.08420 444 | 109 183 0.06517 445 | 109 215 0.06179 446 | 109 218 0.07179 447 | 108 110 0.06803 448 | 108 122 0.08214 449 | 108 135 0.11644 450 | 108 139 0.07724 451 | 108 156 0.10525 452 | 108 181 0.10766 453 | 108 196 0.03132 454 | 108 205 0.08755 455 | 108 214 0.09401 456 | 108 219 0.11157 457 | 107 130 0.11436 458 | 107 173 0.08976 459 | 107 200 0.08254 460 | 107 203 0.11594 461 | 106 123 0.11362 462 | 106 131 0.02227 463 | 106 143 0.06821 464 | 106 179 0.11930 465 | 106 193 0.02119 466 | 106 243 0.10940 467 | 106 246 0.11883 468 | 105 106 0.01034 469 | 105 123 0.10392 470 | 105 131 0.03234 471 | 105 143 0.07217 472 | 105 193 0.03141 473 | 105 243 0.11674 474 | 105 246 0.11604 475 | 104 144 0.08161 476 | 104 185 0.07936 477 | 104 201 0.02597 478 | 104 217 0.09568 479 | 104 232 0.04888 480 | 104 248 0.06640 481 | 103 174 0.03708 482 | 103 192 0.04287 483 | 103 243 0.05731 484 | 102 138 0.09831 485 | 102 187 0.09374 486 | 102 226 0.07775 487 | 102 240 0.11740 488 | 101 108 0.05491 489 | 101 110 0.07783 490 | 101 122 0.05090 491 | 101 125 0.10521 492 | 101 139 0.03983 493 | 101 156 0.09930 494 | 101 157 0.10869 495 | 101 181 0.10336 496 | 101 196 0.03115 497 | 101 205 0.05734 498 | 101 214 0.10662 499 | 101 219 0.10279 500 | 100 103 0.06580 501 | 100 133 0.08099 502 | 100 174 0.06827 503 | 100 192 0.07056 504 | 99 129 0.10765 505 | 99 140 0.05150 506 | 99 147 0.03171 507 | 99 162 0.06455 508 | 98 117 0.11425 509 | 98 178 0.05183 510 | 98 236 0.04433 511 | 97 144 0.07138 512 | 97 160 0.08756 513 | 97 168 0.10904 514 | 97 176 0.10973 515 | 97 185 0.07779 516 | 97 191 0.11562 517 | 97 202 0.08870 518 | 97 204 0.04951 519 | 97 225 0.05664 520 | 97 231 0.10938 521 | 97 248 0.08598 522 | 96 199 0.01569 523 | 96 237 0.06553 524 | 95 115 0.09423 525 | 95 153 0.11710 526 | 95 216 0.11785 527 | 94 141 0.08070 528 | 94 198 0.09053 529 | 94 242 0.09095 530 | 93 97 0.07550 531 | 93 144 0.08371 532 | 93 160 0.04360 533 | 93 168 0.03641 534 | 93 176 0.10570 535 | 93 185 0.11051 536 | 93 187 0.07640 537 | 93 191 0.09704 538 | 93 202 0.11502 539 | 93 204 0.07908 540 | 93 226 0.11188 541 | 93 231 0.03594 542 | 93 248 0.09608 543 | 92 122 0.11702 544 | 92 132 0.07972 545 | 92 139 0.11349 546 | 92 171 0.08961 547 | 92 172 0.09296 548 | 92 205 0.11628 549 | 92 235 0.06040 550 | 91 109 0.06129 551 | 91 119 0.09388 552 | 91 134 0.09544 553 | 91 137 0.01061 554 | 91 145 0.11905 555 | 91 146 0.02723 556 | 91 218 0.04088 557 | 91 224 0.09863 558 | 91 227 0.06960 559 | 90 113 0.11828 560 | 90 173 0.06973 561 | 90 233 0.10517 562 | 90 242 0.10115 563 | 89 116 0.06089 564 | 89 127 0.10682 565 | 89 130 0.10584 566 | 89 164 0.07494 567 | 89 194 0.05110 568 | 88 98 0.08567 569 | 88 182 0.09779 570 | 87 111 0.11190 571 | 87 130 0.03684 572 | 87 136 0.10342 573 | 87 194 0.08273 574 | 87 234 0.08302 575 | 86 108 0.11578 576 | 86 135 0.10345 577 | 86 141 0.05640 578 | 85 152 0.10662 579 | 85 175 0.11147 580 | 85 246 0.09698 581 | 84 100 0.09532 582 | 84 103 0.05747 583 | 84 106 0.11963 584 | 84 131 0.10014 585 | 84 174 0.02770 586 | 84 179 0.06994 587 | 84 192 0.10034 588 | 84 193 0.09844 589 | 84 243 0.07221 590 | 83 95 0.11982 591 | 83 104 0.08511 592 | 83 201 0.09238 593 | 83 217 0.03695 594 | 83 232 0.06812 595 | 82 85 0.04344 596 | 82 152 0.06590 597 | 82 175 0.11914 598 | 82 207 0.10290 599 | 82 212 0.10888 600 | 82 244 0.09913 601 | 82 246 0.09265 602 | 81 119 0.08225 603 | 81 134 0.04508 604 | 81 146 0.11254 605 | 81 227 0.07588 606 | 81 229 0.10166 607 | 80 97 0.08938 608 | 80 149 0.09615 609 | 80 202 0.11386 610 | 80 204 0.10423 611 | 80 225 0.05577 612 | 79 84 0.09700 613 | 79 110 0.11633 614 | 79 174 0.10110 615 | 79 179 0.07431 616 | 79 212 0.11328 617 | 79 214 0.09294 618 | 78 112 0.10817 619 | 78 128 0.03633 620 | 78 138 0.09955 621 | 78 159 0.11389 622 | 78 239 0.02065 623 | 78 240 0.09536 624 | 77 78 0.10966 625 | 77 102 0.02737 626 | 77 138 0.07171 627 | 77 151 0.11765 628 | 77 187 0.10655 629 | 77 208 0.11848 630 | 77 226 0.08175 631 | 77 240 0.09031 632 | 76 95 0.07370 633 | 76 115 0.03658 634 | 76 153 0.04395 635 | 76 228 0.09469 636 | 76 241 0.08004 637 | 75 89 0.03394 638 | 75 116 0.02706 639 | 75 164 0.04846 640 | 75 190 0.10387 641 | 75 194 0.06452 642 | 75 220 0.09669 643 | 75 247 0.10191 644 | 74 109 0.10730 645 | 74 126 0.07749 646 | 74 183 0.05190 647 | 74 215 0.04643 648 | 73 120 0.10775 649 | 73 145 0.09149 650 | 72 107 0.11731 651 | 72 150 0.08210 652 | 72 177 0.06434 653 | 72 186 0.09359 654 | 72 189 0.03706 655 | 72 200 0.08158 656 | 72 203 0.03470 657 | 72 220 0.10329 658 | 72 249 0.07452 659 | 71 135 0.10448 660 | 71 148 0.09121 661 | 71 157 0.10574 662 | 71 181 0.08837 663 | 71 184 0.09326 664 | 71 188 0.03894 665 | 71 230 0.05108 666 | 71 233 0.07728 667 | 71 240 0.11683 668 | 70 79 0.01576 669 | 70 84 0.08129 670 | 70 100 0.11309 671 | 70 174 0.08574 672 | 70 179 0.06528 673 | 70 212 0.11795 674 | 70 214 0.10735 675 | 70 244 0.11957 676 | 69 107 0.05640 677 | 69 128 0.11896 678 | 69 173 0.05282 679 | 68 114 0.06736 680 | 68 160 0.10388 681 | 68 165 0.10769 682 | 68 176 0.04396 683 | 68 191 0.04982 684 | 68 202 0.07329 685 | 68 204 0.10336 686 | 68 222 0.06811 687 | 67 83 0.07338 688 | 67 112 0.11331 689 | 67 217 0.04501 690 | 66 149 0.07561 691 | 66 206 0.05154 692 | 66 209 0.11107 693 | 65 71 0.06843 694 | 65 125 0.10535 695 | 65 138 0.11370 696 | 65 148 0.07162 697 | 65 151 0.10304 698 | 65 157 0.08838 699 | 65 181 0.10922 700 | 65 184 0.04790 701 | 65 188 0.03552 702 | 65 197 0.09301 703 | 65 208 0.10677 704 | 65 230 0.05007 705 | 65 240 0.11415 706 | 64 91 0.04394 707 | 64 109 0.06144 708 | 64 119 0.06813 709 | 64 134 0.09237 710 | 64 137 0.03977 711 | 64 145 0.07791 712 | 64 146 0.04384 713 | 64 183 0.09898 714 | 64 215 0.11174 715 | 64 218 0.08298 716 | 64 227 0.08490 717 | 63 96 0.02231 718 | 63 199 0.01821 719 | 63 237 0.04962 720 | 62 71 0.10901 721 | 62 78 0.11140 722 | 62 90 0.08635 723 | 62 128 0.11744 724 | 62 138 0.09478 725 | 62 188 0.11357 726 | 62 233 0.03192 727 | 62 239 0.10804 728 | 62 240 0.07405 729 | 61 87 0.05163 730 | 61 89 0.09050 731 | 61 111 0.06739 732 | 61 130 0.06867 733 | 61 194 0.07466 734 | 61 234 0.10977 735 | 60 63 0.06637 736 | 60 96 0.05690 737 | 60 111 0.08712 738 | 60 199 0.04868 739 | 60 237 0.11595 740 | 59 80 0.06845 741 | 59 97 0.06442 742 | 59 144 0.08084 743 | 59 185 0.06135 744 | 59 204 0.10796 745 | 59 225 0.08326 746 | 59 248 0.08763 747 | 58 68 0.04795 748 | 58 114 0.01947 749 | 58 163 0.07425 750 | 58 176 0.06845 751 | 58 191 0.08507 752 | 58 202 0.06778 753 | 58 204 0.10891 754 | 58 209 0.09540 755 | 58 211 0.08501 756 | 58 222 0.02759 757 | 57 65 0.06750 758 | 57 118 0.08024 759 | 57 125 0.06349 760 | 57 148 0.06092 761 | 57 151 0.10773 762 | 57 157 0.06773 763 | 57 172 0.11673 764 | 57 181 0.11710 765 | 57 184 0.03368 766 | 57 188 0.10123 767 | 57 197 0.02583 768 | 57 208 0.11002 769 | 57 230 0.08049 770 | 56 73 0.05918 771 | 56 119 0.11916 772 | 56 120 0.05027 773 | 56 145 0.08552 774 | 56 161 0.11851 775 | 55 67 0.08505 776 | 55 78 0.08955 777 | 55 112 0.04590 778 | 55 128 0.09745 779 | 55 136 0.10111 780 | 55 159 0.08414 781 | 55 217 0.11852 782 | 55 239 0.09744 783 | 54 99 0.08037 784 | 54 117 0.08936 785 | 54 140 0.02922 786 | 54 147 0.07003 787 | 53 56 0.05542 788 | 53 73 0.10372 789 | 53 81 0.11179 790 | 53 119 0.07620 791 | 53 120 0.02782 792 | 53 134 0.10851 793 | 53 145 0.06902 794 | 53 229 0.09315 795 | 52 77 0.10533 796 | 52 93 0.09973 797 | 52 102 0.10130 798 | 52 151 0.03422 799 | 52 168 0.06388 800 | 52 187 0.03447 801 | 52 208 0.03135 802 | 52 226 0.02384 803 | 52 231 0.06392 804 | 51 70 0.07990 805 | 51 79 0.06984 806 | 51 86 0.10847 807 | 51 110 0.11491 808 | 51 133 0.11676 809 | 51 214 0.10713 810 | 50 59 0.04226 811 | 50 80 0.10173 812 | 50 97 0.10154 813 | 50 104 0.11784 814 | 50 144 0.08851 815 | 50 185 0.05942 816 | 50 201 0.09673 817 | 50 232 0.11667 818 | 50 248 0.08802 819 | 49 59 0.08296 820 | 49 80 0.08196 821 | 49 93 0.08739 822 | 49 97 0.03121 823 | 49 144 0.10234 824 | 49 160 0.08334 825 | 49 176 0.08610 826 | 49 185 0.10833 827 | 49 191 0.09628 828 | 49 202 0.05875 829 | 49 204 0.02568 830 | 49 222 0.10927 831 | 49 225 0.03314 832 | 49 248 0.11708 833 | 48 50 0.09958 834 | 48 83 0.08782 835 | 48 104 0.06005 836 | 48 144 0.11407 837 | 48 185 0.09500 838 | 48 201 0.03841 839 | 48 216 0.07531 840 | 48 217 0.11710 841 | 48 232 0.02109 842 | 48 248 0.10057 843 | 47 64 0.10444 844 | 47 91 0.06658 845 | 47 109 0.07505 846 | 47 137 0.06569 847 | 47 146 0.09071 848 | 47 167 0.11422 849 | 47 218 0.02914 850 | 47 224 0.05238 851 | 46 161 0.07892 852 | 46 169 0.06854 853 | 46 177 0.11118 854 | 46 186 0.07689 855 | 45 48 0.11127 856 | 45 67 0.06225 857 | 45 76 0.11037 858 | 45 83 0.02906 859 | 45 95 0.10135 860 | 45 104 0.11417 861 | 45 217 0.04535 862 | 45 232 0.09323 863 | 44 49 0.02107 864 | 44 59 0.09573 865 | 44 68 0.11930 866 | 44 80 0.10281 867 | 44 93 0.06793 868 | 44 97 0.03365 869 | 44 144 0.09765 870 | 44 160 0.06268 871 | 44 168 0.10433 872 | 44 176 0.07613 873 | 44 185 0.10945 874 | 44 191 0.08240 875 | 44 202 0.05971 876 | 44 204 0.01774 877 | 44 222 0.11370 878 | 44 225 0.05336 879 | 44 231 0.10384 880 | 44 248 0.11288 881 | 43 82 0.08576 882 | 43 152 0.08933 883 | 43 156 0.10122 884 | 43 207 0.02708 885 | 43 210 0.05763 886 | 43 212 0.07554 887 | 43 219 0.09405 888 | 43 221 0.03765 889 | 43 244 0.10274 890 | 42 86 0.09639 891 | 42 101 0.09688 892 | 42 108 0.06664 893 | 42 135 0.05008 894 | 42 141 0.08880 895 | 42 157 0.11467 896 | 42 181 0.06506 897 | 42 196 0.09113 898 | 41 81 0.11854 899 | 41 88 0.06374 900 | 41 121 0.07816 901 | 41 170 0.09973 902 | 41 182 0.03878 903 | 41 198 0.10323 904 | 40 75 0.07166 905 | 40 89 0.10329 906 | 40 116 0.05100 907 | 40 150 0.07051 908 | 40 164 0.03395 909 | 40 190 0.03649 910 | 40 194 0.10624 911 | 40 220 0.03150 912 | 40 247 0.07741 913 | 39 66 0.05590 914 | 39 80 0.10277 915 | 39 149 0.05382 916 | 39 206 0.10412 917 | 39 209 0.10654 918 | 39 211 0.11209 919 | 38 74 0.06907 920 | 38 109 0.09245 921 | 38 126 0.00845 922 | 38 183 0.08279 923 | 38 215 0.05290 924 | 37 76 0.02674 925 | 37 95 0.09352 926 | 37 115 0.01398 927 | 37 153 0.03846 928 | 37 228 0.07596 929 | 37 241 0.06139 930 | 36 41 0.05329 931 | 36 88 0.01841 932 | 36 98 0.08515 933 | 36 182 0.09055 934 | 35 36 0.08804 935 | 35 41 0.10606 936 | 35 88 0.07142 937 | 35 94 0.06254 938 | 35 141 0.11388 939 | 35 198 0.10645 940 | 34 53 0.08565 941 | 34 56 0.04399 942 | 34 73 0.01812 943 | 34 120 0.09075 944 | 34 145 0.07784 945 | 33 58 0.09102 946 | 33 114 0.08593 947 | 33 163 0.10678 948 | 33 222 0.10644 949 | 32 52 0.07988 950 | 32 77 0.11466 951 | 32 93 0.07410 952 | 32 102 0.09251 953 | 32 104 0.10076 954 | 32 144 0.07333 955 | 32 151 0.11408 956 | 32 160 0.11627 957 | 32 168 0.05434 958 | 32 185 0.10165 959 | 32 187 0.04594 960 | 32 201 0.11801 961 | 32 208 0.11121 962 | 32 226 0.07421 963 | 32 231 0.05700 964 | 32 248 0.07367 965 | 31 37 0.09487 966 | 31 115 0.08730 967 | 31 153 0.10769 968 | 31 228 0.07913 969 | 31 241 0.07871 970 | 30 43 0.10126 971 | 30 70 0.10835 972 | 30 79 0.10818 973 | 30 82 0.10926 974 | 30 143 0.08740 975 | 30 152 0.04565 976 | 30 156 0.11364 977 | 30 179 0.06570 978 | 30 207 0.08708 979 | 30 210 0.09124 980 | 30 212 0.03314 981 | 30 214 0.11280 982 | 30 219 0.11146 983 | 30 221 0.11496 984 | 30 244 0.01475 985 | 29 47 0.02921 986 | 29 64 0.10752 987 | 29 91 0.06429 988 | 29 109 0.09440 989 | 29 137 0.06803 990 | 29 146 0.08191 991 | 29 167 0.10821 992 | 29 218 0.02524 993 | 29 224 0.03477 994 | 29 227 0.10208 995 | 28 35 0.10487 996 | 28 41 0.10902 997 | 28 94 0.08477 998 | 28 113 0.05483 999 | 28 121 0.07801 1000 | 28 170 0.10987 1001 | 28 182 0.08584 1002 | 28 198 0.00775 1003 | 28 223 0.09677 1004 | 28 242 0.02503 1005 | 27 62 0.07419 1006 | 27 65 0.07207 1007 | 27 71 0.05107 1008 | 27 138 0.07814 1009 | 27 184 0.11544 1010 | 27 188 0.03989 1011 | 27 230 0.08817 1012 | 27 233 0.04883 1013 | 27 240 0.06581 1014 | 26 55 0.09933 1015 | 26 77 0.03854 1016 | 26 78 0.09413 1017 | 26 102 0.04190 1018 | 26 138 0.09654 1019 | 26 217 0.11910 1020 | 26 226 0.11644 1021 | 26 239 0.11461 1022 | 26 240 0.11097 1023 | 25 60 0.03405 1024 | 25 63 0.09366 1025 | 25 96 0.08879 1026 | 25 111 0.05309 1027 | 25 199 0.07779 1028 | 24 39 0.07951 1029 | 24 66 0.08457 1030 | 24 80 0.11814 1031 | 24 114 0.10397 1032 | 24 149 0.02915 1033 | 24 163 0.05034 1034 | 24 206 0.09602 1035 | 24 209 0.02802 1036 | 24 211 0.03696 1037 | 24 222 0.09835 1038 | 24 225 0.11996 1039 | 23 33 0.06032 1040 | 23 58 0.07072 1041 | 23 68 0.07437 1042 | 23 114 0.07960 1043 | 23 176 0.11709 1044 | 23 195 0.08090 1045 | 23 222 0.09692 1046 | 22 34 0.03658 1047 | 22 53 0.07033 1048 | 22 56 0.01508 1049 | 22 73 0.04871 1050 | 22 120 0.06464 1051 | 22 145 0.09324 1052 | 21 27 0.01873 1053 | 21 62 0.07424 1054 | 21 65 0.07811 1055 | 21 71 0.03782 1056 | 21 138 0.09594 1057 | 21 184 0.11666 1058 | 21 188 0.04280 1059 | 21 230 0.08276 1060 | 21 233 0.04409 1061 | 21 240 0.08207 1062 | 20 40 0.07068 1063 | 20 75 0.02897 1064 | 20 89 0.05690 1065 | 20 116 0.02095 1066 | 20 127 0.11837 1067 | 20 164 0.06088 1068 | 20 190 0.09529 1069 | 20 194 0.09349 1070 | 20 220 0.10072 1071 | 20 247 0.07725 1072 | 19 70 0.06872 1073 | 19 79 0.08364 1074 | 19 84 0.03540 1075 | 19 100 0.06397 1076 | 19 103 0.05319 1077 | 19 174 0.01925 1078 | 19 179 0.08733 1079 | 19 192 0.09085 1080 | 19 243 0.09323 1081 | 18 35 0.11609 1082 | 18 51 0.11645 1083 | 18 86 0.02813 1084 | 18 94 0.11772 1085 | 18 141 0.06466 1086 | 17 41 0.10519 1087 | 17 81 0.05763 1088 | 17 121 0.09728 1089 | 17 134 0.10171 1090 | 17 158 0.10542 1091 | 17 170 0.07756 1092 | 17 182 0.09423 1093 | 17 223 0.11337 1094 | 17 229 0.06676 1095 | 16 54 0.07406 1096 | 16 98 0.11623 1097 | 16 99 0.10210 1098 | 16 117 0.05134 1099 | 16 129 0.09325 1100 | 16 140 0.07952 1101 | 16 147 0.07171 1102 | 16 166 0.11475 1103 | 16 178 0.06981 1104 | 16 236 0.07388 1105 | 15 24 0.04507 1106 | 15 39 0.09051 1107 | 15 49 0.10519 1108 | 15 58 0.10462 1109 | 15 66 0.11797 1110 | 15 80 0.08217 1111 | 15 114 0.09104 1112 | 15 149 0.04256 1113 | 15 163 0.05589 1114 | 15 202 0.08786 1115 | 15 204 0.11074 1116 | 15 209 0.04580 1117 | 15 211 0.04000 1118 | 15 222 0.07726 1119 | 15 225 0.07498 1120 | 14 18 0.07335 1121 | 14 51 0.09603 1122 | 14 86 0.09145 1123 | 14 129 0.10737 1124 | 14 133 0.06649 1125 | 14 166 0.08096 1126 | 13 19 0.08927 1127 | 13 100 0.02560 1128 | 13 103 0.08741 1129 | 13 129 0.10843 1130 | 13 133 0.06257 1131 | 13 162 0.11602 1132 | 13 174 0.09377 1133 | 13 192 0.08128 1134 | 12 28 0.06032 1135 | 12 35 0.06079 1136 | 12 36 0.08058 1137 | 12 41 0.06364 1138 | 12 88 0.07461 1139 | 12 94 0.08239 1140 | 12 113 0.09906 1141 | 12 121 0.08542 1142 | 12 170 0.11918 1143 | 12 182 0.06361 1144 | 12 198 0.05807 1145 | 12 242 0.08457 1146 | 11 30 0.08689 1147 | 11 43 0.10208 1148 | 11 82 0.03687 1149 | 11 85 0.06928 1150 | 11 143 0.08708 1151 | 11 152 0.04140 1152 | 11 175 0.09935 1153 | 11 207 0.11101 1154 | 11 212 0.09716 1155 | 11 244 0.07397 1156 | 11 246 0.06678 1157 | 10 105 0.11028 1158 | 10 106 0.11976 1159 | 10 123 0.00886 1160 | 10 175 0.07429 1161 | 10 246 0.09977 1162 | 9 23 0.03526 1163 | 9 33 0.08216 1164 | 9 58 0.10398 1165 | 9 68 0.09604 1166 | 9 114 0.11445 1167 | 9 142 0.10955 1168 | 9 195 0.04585 1169 | 8 11 0.04709 1170 | 8 30 0.03985 1171 | 8 43 0.09334 1172 | 8 82 0.07286 1173 | 8 85 0.11331 1174 | 8 143 0.07437 1175 | 8 152 0.00702 1176 | 8 179 0.09533 1177 | 8 207 0.09011 1178 | 8 210 0.10661 1179 | 8 212 0.05604 1180 | 8 221 0.11895 1181 | 8 244 0.02711 1182 | 8 246 0.09709 1183 | 7 42 0.11616 1184 | 7 57 0.06795 1185 | 7 65 0.09235 1186 | 7 71 0.11091 1187 | 7 101 0.10577 1188 | 7 125 0.02442 1189 | 7 148 0.02175 1190 | 7 157 0.00516 1191 | 7 181 0.05778 1192 | 7 184 0.04976 1193 | 7 188 0.10982 1194 | 7 197 0.06984 1195 | 7 230 0.06107 1196 | 6 16 0.04529 1197 | 6 54 0.11235 1198 | 6 98 0.09893 1199 | 6 99 0.11022 1200 | 6 117 0.08821 1201 | 6 129 0.05363 1202 | 6 140 0.10829 1203 | 6 147 0.07924 1204 | 6 166 0.06998 1205 | 6 178 0.07007 1206 | 6 236 0.05556 1207 | 5 26 0.03351 1208 | 5 32 0.11054 1209 | 5 55 0.11131 1210 | 5 67 0.10880 1211 | 5 77 0.05505 1212 | 5 102 0.03834 1213 | 5 104 0.11574 1214 | 5 217 0.09458 1215 | 5 226 0.11433 1216 | 4 5 0.11184 1217 | 4 26 0.08347 1218 | 4 55 0.06425 1219 | 4 77 0.10733 1220 | 4 78 0.02559 1221 | 4 112 0.08751 1222 | 4 128 0.04751 1223 | 4 138 0.11375 1224 | 4 159 0.10114 1225 | 4 239 0.03883 1226 | 4 240 0.11344 1227 | 3 37 0.08512 1228 | 3 45 0.11902 1229 | 3 67 0.09725 1230 | 3 76 0.08069 1231 | 3 115 0.09861 1232 | 3 153 0.04799 1233 | 3 228 0.07635 1234 | 3 241 0.07024 1235 | 2 14 0.08765 1236 | 2 18 0.07425 1237 | 2 42 0.11456 1238 | 2 51 0.05083 1239 | 2 79 0.11759 1240 | 2 86 0.05980 1241 | 2 108 0.09627 1242 | 2 110 0.11746 1243 | 2 141 0.11373 1244 | 1 72 0.06506 1245 | 1 107 0.07484 1246 | 1 130 0.10203 1247 | 1 150 0.10908 1248 | 1 164 0.11039 1249 | 1 189 0.09582 1250 | 1 194 0.11069 1251 | 1 200 0.09550 1252 | 1 203 0.08567 1253 | 1 220 0.10428 1254 | 0 15 0.05719 1255 | 0 24 0.10191 1256 | 0 44 0.06471 1257 | 0 49 0.04849 1258 | 0 58 0.09955 1259 | 0 59 0.10657 1260 | 0 68 0.11816 1261 | 0 80 0.06821 1262 | 0 97 0.07705 1263 | 0 114 0.09610 1264 | 0 149 0.09659 1265 | 0 160 0.11714 1266 | 0 163 0.09368 1267 | 0 176 0.08927 1268 | 0 191 0.10711 1269 | 0 202 0.04678 1270 | 0 204 0.05476 1271 | 0 209 0.09511 1272 | 0 211 0.08438 1273 | 0 222 0.07573 1274 | 0 225 0.02383 -------------------------------------------------------------------------------- /chapter_09_shortest_path/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwang96-dl/play-with-algorithms/fa34ae2c17e75b3d233b1426094ce66229090a37/chapter_09_shortest_path/__init__.py -------------------------------------------------------------------------------- /chapter_09_shortest_path/bellman_ford.py: -------------------------------------------------------------------------------- 1 | from chapter_08_minimum_span_tree.edge import Edge 2 | 3 | 4 | class BellmanFord: 5 | def __init__(self, graph, s): 6 | self._G = graph 7 | self._s = s 8 | self._dist_to = [0] * self._G.V() 9 | self._from = [None] * self._G.V() 10 | self._has_negative_cycle = False 11 | # Bellman-Ford 12 | self._dist_to[self._s] = 0 13 | self._from[s] = Edge(self._s, self._s, 0) 14 | for index in range(1, self._G.V()): 15 | # relaxation 16 | for i in range(self._G.V()): 17 | for e in self._G[i]: 18 | if self._dist_to[e.v()] + e.wt() < self._dist_to[e.w()] or \ 19 | not self._from[e.w()]: 20 | self._dist_to[e.w()] = self._dist_to[e.v()] + e.wt() 21 | self._from[e.w()] = e 22 | self._has_negative_cycle = self._detect_negative_cycle() 23 | 24 | def _detect_negative_cycle(self): 25 | for i in range(self._G.V()): 26 | for e in self._G[i]: 27 | if self._dist_to[e.v()] + e.wt() < self._dist_to[e.w()] or \ 28 | not self._from[e.w()]: 29 | return True 30 | return False 31 | 32 | def negative_cycle(self): 33 | return self._has_negative_cycle 34 | 35 | def shortest_path_to(self, w): 36 | assert 0 <= w < self._G.V() 37 | assert not self._has_negative_cycle 38 | assert self.has_path_to(w) 39 | return self._dist_to[w] 40 | 41 | def has_path_to(self, w): 42 | assert 0 <= w < self._G.V() 43 | return self._from[w] is not None 44 | 45 | def shortest_path(self, w): 46 | assert 0 <= w < self._G.V() 47 | assert not self._has_negative_cycle 48 | assert self.has_path_to(w) 49 | s = [] 50 | e = self._from[w] 51 | while e.v() != self._s: 52 | s.append(e) 53 | e = self._from[e.v()] 54 | s.append(e) 55 | return s[::-1] 56 | 57 | def show_path(self, w): 58 | assert 0 <= w < self._G.V() 59 | assert not self._has_negative_cycle 60 | assert self.has_path_to(w) 61 | vec = self.shortest_path(w) 62 | print('Shortest path from {} to {}: {}'.format( 63 | self._s, 64 | w, 65 | '{} -> '.format(self._s) + ' -> '.join(str(i.w()) for i in vec)) 66 | ) -------------------------------------------------------------------------------- /chapter_09_shortest_path/dijkstra.py: -------------------------------------------------------------------------------- 1 | from chapter_04_heap_sort.heap_sort import IndexMinHeap 2 | from chapter_08_minimum_span_tree.edge import Edge 3 | 4 | 5 | class Dijkstra: 6 | def __init__(self, graph, s): 7 | self._G = graph 8 | assert 0 <= s < self._G.V() 9 | self._s = s 10 | self._dist_to = [0] * self._G.V() 11 | self._marked = [False] * self._G.V() 12 | self._from = [None] * self._G.V() 13 | self._ipq = IndexMinHeap(self._G.V()) 14 | self._dist_to[s] = 0 15 | self._from[s] = Edge(s, s, 0) 16 | self._ipq.insert(s, self._dist_to[s]) 17 | self._marked[s] = True 18 | while not self._ipq.is_empty(): 19 | v = self._ipq.extract_min_index() 20 | self._marked[v] = True 21 | for e in self._G[v]: 22 | w = e.other(v) 23 | if not self._marked[w]: 24 | if not self._from[w] or self._dist_to[v] + e.wt() < self._dist_to[w]: 25 | self._dist_to[w] = self._dist_to[v] + e.wt() 26 | self._from[w] = e 27 | if self._ipq._contains(w): 28 | self._ipq.change(w, self._dist_to[w]) 29 | else: 30 | self._ipq.insert(w, self._dist_to[w]) 31 | 32 | def shortest_path_to(self, w): 33 | assert 0 <= w < self._G.V() 34 | assert self.has_path_to(w) 35 | return self._dist_to[w] 36 | 37 | def has_path_to(self, w): 38 | assert 0 <= w < self._G.V() 39 | return self._marked[w] 40 | 41 | def shortest_path(self, w): 42 | assert 0 <= w < self._G.V() 43 | assert self.has_path_to(w) 44 | s = [] 45 | e = self._from[w] 46 | while e.v() != self._s: 47 | s.append(e) 48 | e = self._from[e.v()] 49 | s.append(e) 50 | return s[::-1] 51 | 52 | def show_path(self, w): 53 | assert 0 <= w < self._G.V() 54 | assert self.has_path_to(w) 55 | vec = self.shortest_path(w) 56 | print('Shortest path from {} to {}: {}'.format( 57 | self._s, 58 | w, 59 | '{} -> '.format(self._s) + ' -> '.join(str(i.w()) for i in vec)) 60 | ) -------------------------------------------------------------------------------- /chapter_09_shortest_path/main.py: -------------------------------------------------------------------------------- 1 | from chapter_08_minimum_span_tree.sparse_graph import SparseGraph 2 | from chapter_09_shortest_path.dijkstra import Dijkstra 3 | from chapter_09_shortest_path.bellman_ford import BellmanFord 4 | 5 | 6 | 7 | if __name__ == '__main__': 8 | sparse_graph = SparseGraph.from_local_file( 9 | directed=True, 10 | filename='./chapter_09_shortest_path/testG1.txt', 11 | ) 12 | dij = Dijkstra(sparse_graph, 0) 13 | 14 | print('Dijkstra: ') 15 | for w in range(5): 16 | dij.show_path(w) 17 | 18 | sparse_graph2 = SparseGraph.from_local_file( 19 | directed=True, 20 | filename='./chapter_09_shortest_path/testG2.txt', 21 | ) 22 | bell = BellmanFord(sparse_graph2, 0) 23 | print('Bellman-Ford: ') 24 | if bell.negative_cycle(): 25 | print('The graph contains gegative cycle!') 26 | else: 27 | for w in range(5): 28 | bell.show_path(w) -------------------------------------------------------------------------------- /chapter_09_shortest_path/testG1.txt: -------------------------------------------------------------------------------- 1 | 5 8 2 | 0 1 5 3 | 0 2 2 4 | 0 3 6 5 | 1 4 1 6 | 2 1 1 7 | 2 4 5 8 | 2 3 3 9 | 3 4 2 -------------------------------------------------------------------------------- /chapter_09_shortest_path/testG2.txt: -------------------------------------------------------------------------------- 1 | 5 8 2 | 0 1 5 3 | 0 2 2 4 | 0 3 6 5 | 1 2 -4 6 | 1 4 2 7 | 2 4 5 8 | 2 3 3 9 | 4 3 -3 -------------------------------------------------------------------------------- /sort_test_helper/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwang96-dl/play-with-algorithms/fa34ae2c17e75b3d233b1426094ce66229090a37/sort_test_helper/__init__.py -------------------------------------------------------------------------------- /sort_test_helper/helpers.py: -------------------------------------------------------------------------------- 1 | import random 2 | from time import time 3 | from random import randint 4 | 5 | 6 | def generate_random_array(n, range_l, range_r): 7 | random.seed(time()) 8 | return [randint(range_l, range_r) for _ in range(n)] 9 | 10 | 11 | def generate_nearly_ordered_random_array(n, range_l, range_r, swap_times): 12 | random.seed(time()) 13 | ret = [i for i in range(n)] 14 | for _ in range(swap_times): 15 | pos_x, pos_y = randint(0, n - 1), randint(0, n - 1) 16 | ret[pos_x], ret[pos_y] = ret[pos_y], ret[pos_x] 17 | return ret 18 | 19 | 20 | def test_sort(sort_name, sort_func, arr): 21 | start_time = time() 22 | sort_func(arr) 23 | print('<{}> costs {:.5f} seconds to sort a length of {} array.'.format( 24 | sort_name, 25 | time() - start_time, 26 | len(arr), 27 | )) 28 | assert is_sorted(arr), '<{}> is wrong!'.format(sort_name) 29 | 30 | 31 | def is_sorted(arr): 32 | for i in range(len(arr) - 1): 33 | if arr[i] > arr[i + 1]: 34 | return False 35 | return True 36 | 37 | 38 | def union_find_test_helper(uf, n, uf_name): 39 | start_time = time() 40 | for _ in range(n): 41 | uf.union(randint(0, n - 1), randint(0, n - 1)) 42 | for _ in range(n): 43 | uf.is_connected(randint(0, n - 1), randint(0, n - 1)) 44 | print('{} time costs: {:.5f}'.format(uf_name, time() - start_time)) --------------------------------------------------------------------------------