├── .gitignore ├── .travis.yml ├── LICENSE.md ├── README.md ├── algorithms ├── __init__.py ├── bubblesort.py ├── heapsort.py ├── insertionsort.py ├── mergesort.py ├── quicksort.py └── selectionsort.py ├── images └── example.gif ├── sorting.py ├── tests └── test_sort.py └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.pyc 3 | 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.3" 4 | - "3.4" 5 | - "3.5" 6 | - "3.5-dev" # 3.5 development branch 7 | - "3.6-dev" # 3.6 development branch 8 | # command to run tests 9 | script: 10 | - python -m unittest discover tests 11 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 ming 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sorting 2 | [![travis](https://travis-ci.org/mingrammer/sorting.svg?branch=master)](https://travis-ci.org/mingrammer/sorting) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) 3 | 4 | Visualize the process of sorting algorithms simply 5 | 6 | Now it shows just each completed steps, so I'll support the code tracing for visualizing the every steps including swapping later. 7 | 8 | ![example](images/example.gif) 9 | 10 | ## Run 11 | 1. Clone this repository to your machine 12 | 2. Just `python3 sorting.py` 13 | 14 | ## Usage commands 15 | There are very few commands. 16 | 17 | * **create** \< length of list \> : Create list with given length. 18 | * **mergesort** : Sort the list using mergesort algorithm. 19 | * **heapsort** : Sort the list using heapsort algorithm. 20 | 21 | ## Supported Sorting Algorithms 22 | * MergeSort 23 | * HeapSort 24 | * QuickSort (not implementd yet) 25 | * BubbleSort (not implementd yet) 26 | * InsertionSort (not implementd yet) 27 | * SelectionSort (not implementd yet) 28 | 29 | 30 | ## Contribution 31 | Welcome any contributions of new sorting algorithms 32 | 33 | You should just follow the PEP8! 34 | -------------------------------------------------------------------------------- /algorithms/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mingrammer/sorting/6b4fae14a119a35ef62800bf91b15fe341e08fb7/algorithms/__init__.py -------------------------------------------------------------------------------- /algorithms/bubblesort.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mingrammer/sorting/6b4fae14a119a35ef62800bf91b15fe341e08fb7/algorithms/bubblesort.py -------------------------------------------------------------------------------- /algorithms/heapsort.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | from copy import deepcopy 3 | 4 | 5 | heap_steps = defaultdict() 6 | 7 | 8 | def reset_steps(): 9 | heap_steps.clear() 10 | 11 | 12 | class Heap: 13 | arr = [] 14 | arr_size = 0 15 | size = 0 16 | 17 | def __init__(self, arr, arr_size, heap_size): 18 | self.arr = arr 19 | self.arr_size = arr_size 20 | self.size = heap_size 21 | 22 | 23 | def max_heapify(heap, i): 24 | largest_idx = i 25 | l_idx, r_idx = None, None 26 | 27 | if 2 * i + 1 < heap.size: 28 | l_idx = 2 * i + 1 29 | 30 | if 2 * (i + 1) < heap.size: 31 | r_idx = 2 * (i + 1) 32 | 33 | if l_idx is not None and heap.arr[l_idx] > heap.arr[i]: 34 | largest_idx = l_idx 35 | 36 | if r_idx is not None and heap.arr[r_idx] > heap.arr[largest_idx]: 37 | largest_idx = r_idx 38 | 39 | if largest_idx != i: 40 | heap.arr[i], heap.arr[largest_idx] = heap.arr[largest_idx], heap.arr[i] 41 | max_heapify(heap, largest_idx) 42 | 43 | 44 | def build_max_heap(heap): 45 | for i in range(int(heap.arr_size / 2), -1, -1): 46 | max_heapify(heap, i) 47 | 48 | 49 | def heapsort(arr): 50 | n = 1 51 | reset_steps() 52 | 53 | arr_size = len(arr) 54 | heap_size = arr_size 55 | 56 | heap = Heap(arr, arr_size, heap_size) 57 | 58 | build_max_heap(heap) 59 | 60 | heap_steps[n] = deepcopy(heap) 61 | 62 | for i in range(heap.arr_size - 1, 0, -1): 63 | heap.arr[i], heap.arr[0] = heap.arr[0], heap.arr[i] 64 | heap.size -= 1 65 | max_heapify(heap, 0) 66 | 67 | n += 1 68 | heap_steps[n] = deepcopy(heap) 69 | 70 | return heap.arr 71 | 72 | 73 | def get_heap_steps(): 74 | return heap_steps 75 | -------------------------------------------------------------------------------- /algorithms/insertionsort.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mingrammer/sorting/6b4fae14a119a35ef62800bf91b15fe341e08fb7/algorithms/insertionsort.py -------------------------------------------------------------------------------- /algorithms/mergesort.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | 4 | split_steps = defaultdict(list) 5 | merge_steps = defaultdict(list) 6 | 7 | 8 | def reset_steps(): 9 | split_steps.clear() 10 | merge_steps.clear() 11 | 12 | 13 | def mergesort(arr, n=1): 14 | size = len(arr) 15 | 16 | if n == 1: 17 | reset_steps() 18 | 19 | if size == 1: 20 | return arr 21 | 22 | split_steps[n].append(arr[:size // 2]) 23 | split_steps[n].append(arr[size // 2:]) 24 | 25 | l_arr = mergesort(arr[:size // 2], n + 1) 26 | r_arr = mergesort(arr[size // 2:], n + 1) 27 | 28 | l_size = len(l_arr) 29 | r_size = len(r_arr) 30 | 31 | i, j = 0, 0 32 | 33 | merged = [] 34 | 35 | while i < l_size and j < r_size: 36 | if l_arr[i] < r_arr[j]: 37 | merged.append(l_arr[i]) 38 | i += 1 39 | else: 40 | merged.append(r_arr[j]) 41 | j += 1 42 | 43 | merged.extend(l_arr[i:]) 44 | merged.extend(r_arr[j:]) 45 | 46 | merge_steps[n].append(merged) 47 | 48 | return merged 49 | 50 | 51 | def get_split_steps(): 52 | return split_steps 53 | 54 | 55 | def get_merge_steps(): 56 | return merge_steps 57 | -------------------------------------------------------------------------------- /algorithms/quicksort.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mingrammer/sorting/6b4fae14a119a35ef62800bf91b15fe341e08fb7/algorithms/quicksort.py -------------------------------------------------------------------------------- /algorithms/selectionsort.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mingrammer/sorting/6b4fae14a119a35ef62800bf91b15fe341e08fb7/algorithms/selectionsort.py -------------------------------------------------------------------------------- /images/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mingrammer/sorting/6b4fae14a119a35ef62800bf91b15fe341e08fb7/images/example.gif -------------------------------------------------------------------------------- /sorting.py: -------------------------------------------------------------------------------- 1 | import cmd 2 | import random 3 | import sys 4 | 5 | from algorithms.heapsort import heapsort, get_heap_steps 6 | from algorithms.mergesort import mergesort, get_split_steps, get_merge_steps 7 | from utils import colored_text 8 | 9 | 10 | class SortingShell(cmd.Cmd): 11 | "Simple sorting cmd shell." 12 | 13 | intro = 'Welcome to sorting command line shell :D' 14 | prompt = colored_text('(Sorting) ', 'GREEN') 15 | file = None 16 | 17 | _list = [] 18 | 19 | def emptyline(self, *args): 20 | pass 21 | 22 | def do_create(self, *args): 23 | "Create random list by given length : create " 24 | 25 | size = args[0] 26 | 27 | if not size.isdigit(): 28 | print('Usage : create ') 29 | else: 30 | size = int(size) 31 | 32 | if size > 100 or size < 2: 33 | print('Length of list must be in between 2 and 100') 34 | else: 35 | self._list = [random.randint(1, 1 << 8) for i in range(size)] 36 | print('Created list :', self._list) 37 | 38 | def do_heapsort(self, *args): 39 | "Sort the list using heapsort algorithm : heapsort" 40 | 41 | if len(self._list) == 0: 42 | print('You must create list using "create" command first') 43 | else: 44 | print('Original list :', self._list, '\n') 45 | 46 | print(colored_text('Yello list', 'YELLOW'), ':', 'heap list') 47 | print(colored_text(' Blue list', 'BLUE'), ':', 'sorted list by prepending max\n') 48 | 49 | sorted_list = heapsort(self._list) 50 | 51 | num_heap_steps = len(get_heap_steps().items()) 52 | 53 | for i, heap_step in get_heap_steps().items(): 54 | heap_list = heap_step.arr[:num_heap_steps - i + 1] 55 | non_heap_list = heap_step.arr[num_heap_steps - i + 1:] 56 | 57 | if non_heap_list != []: 58 | print('Heap step {0}'.format(i).ljust(13), ':', 59 | colored_text(str(heap_list)[:-1], 'YELLOW') + ',', 60 | colored_text(str(non_heap_list)[1:], 'BLUE')) 61 | else: 62 | print('Heap step {0}'.format(i).ljust(13), ':', 63 | colored_text(str(heap_list), 'YELLOW')) 64 | else: 65 | print() 66 | 67 | print('Sorted list :', sorted_list) 68 | 69 | def do_mergesort(self, *args): 70 | "Sort the list using mergesort algorithm : mergesort" 71 | 72 | if len(self._list) == 0: 73 | print('You must create list using "create" command first') 74 | else: 75 | print('Original list :', self._list, '\n') 76 | 77 | sorted_list = mergesort(self._list) 78 | 79 | for i, split_step in get_split_steps().items(): 80 | print('Split step {0}'.format(i).ljust(13), ':', 81 | colored_text(' | ', 'BLUE').join([str(e) for e in split_step])) 82 | else: 83 | print() 84 | 85 | num_merge_steps = len(get_merge_steps().items()) 86 | 87 | for i, merge_step in sorted(get_merge_steps().items(), reverse=True): 88 | print('Merge step {0}'.format(num_merge_steps - i + 1).ljust(13), ':', 89 | colored_text(' | ', 'BLUE').join([str(e) for e in merge_step])) 90 | else: 91 | print() 92 | 93 | print('Sorted list :', sorted_list) 94 | 95 | def do_exit(self, *args): 96 | "Exit the shell." 97 | 98 | print('Thank you! Goodbye') 99 | 100 | return True 101 | 102 | 103 | if __name__ == '__main__': 104 | SortingShell().cmdloop() 105 | -------------------------------------------------------------------------------- /tests/test_sort.py: -------------------------------------------------------------------------------- 1 | import random 2 | import unittest 3 | 4 | from algorithms.heapsort import heapsort 5 | from algorithms.mergesort import mergesort 6 | 7 | 8 | class TestSort(unittest.TestCase): 9 | def setUp(self): 10 | self.arr = [random.randint(1, 1000) for _ in range(100)] 11 | 12 | def test_heapsort(self): 13 | heapsorted_arr = heapsort(self.arr) 14 | 15 | self.assertEqual(heapsorted_arr, sorted(self.arr)) 16 | 17 | def test_mergesort(self): 18 | mergesorted_arr = mergesort(self.arr) 19 | 20 | self.assertEqual(mergesorted_arr, sorted(self.arr)) 21 | 22 | 23 | if __name__ == '__main__': 24 | unittest.main() 25 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | class ColorCode: 2 | CGREEN = '\33[32m' 3 | CBLUE = '\33[34m' 4 | CYELLOW = '\33[33m' 5 | CEND = '\033[0m' 6 | 7 | 8 | def colored_text(text, color): 9 | if color in ('green', 'Green', 'GREEN'): 10 | return ColorCode.CGREEN + text + ColorCode.CEND 11 | elif color in ('blue', 'Blue', 'BLUE'): 12 | return ColorCode.CBLUE + text + ColorCode.CEND 13 | elif color in ('yellow', 'Yellow', 'YELLOW'): 14 | return ColorCode.CYELLOW + text + ColorCode.CEND 15 | --------------------------------------------------------------------------------