├── .gitignore ├── README.md ├── bubblesort.py ├── heapsort.py ├── mainpage.py ├── mergesort.py ├── quicksort.py └── selectionsort.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SortingVisualizer 2 | This is a visualization tool for various sorting algorithms 3 | - BubbleSort 4 | - SelectionSort 5 | - MergeSort 6 | - QuickSort 7 | - HeapSort 8 | 9 | 10 | ## Functionalities 11 | - Array size can be changed 12 | - Visualization speed can be adjusted on the fly 13 | 14 | ## Preview 15 | 16 | https://user-images.githubusercontent.com/45568398/124811249-e1f98980-df7f-11eb-817b-966a99ba484d.mp4 17 | 18 | -------------------------------------------------------------------------------- /bubblesort.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | max_time = 0.250 4 | # compares neighbouring elements in the array 5 | def bubbleSort(arr, displayArray, speedInput, pauseBool): 6 | 7 | swapCount = 0 8 | N = len(arr) 9 | for i in range(N): 10 | swapped = False 11 | 12 | for j in range(N - 1): 13 | if arr[j] > arr[j + 1]: 14 | arr[j], arr[j + 1] = arr[j + 1], arr[j] 15 | swapCount += 1 16 | colorArray = ['red'] * N 17 | colorArray[j] = 'blue' 18 | colorArray[j + 1] = 'blue' 19 | if i: 20 | colorArray[-i:] = ['green'] * i 21 | 22 | displayArray(arr, colorArray, swapCount) 23 | time.sleep(max_time - (speedInput() * max_time / 100)) 24 | swapped = True 25 | 26 | if not swapped: 27 | break 28 | 29 | colorArray = ['green'] * N 30 | displayArray(arr, colorArray, swapCount) 31 | print("Sorted arr : ",arr) 32 | 33 | 34 | 35 | # arr = [2, 10,11,25,13,78,1,7,80] 36 | # 37 | # print(bubbleSort(arr)) 38 | -------------------------------------------------------------------------------- /heapsort.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | max_time = 0.250 4 | # compares neighbouring elements in the array 5 | def heapSort(arr, displayArray, speedInput, pauseBool): 6 | 7 | swapCount = 0 8 | N = len(arr) 9 | for heap_length in range(1, N): 10 | while heap_length: 11 | parent = (heap_length - 1) // 2 12 | if arr[heap_length] > arr[parent]: 13 | arr[parent], arr[heap_length] = arr[heap_length], arr[parent] 14 | swapCount += 1 15 | colorArray = ['red'] * N 16 | colorArray[parent] = ['blue'] 17 | colorArray[heap_length] = ['yellow'] 18 | displayArray(arr, colorArray, swapCount) 19 | time.sleep(max_time - (speedInput() * max_time / 100)) 20 | heap_length = parent 21 | 22 | for i in reversed(range(N)): 23 | arr[i], arr[0] = arr[0], arr[i] 24 | swapCount += 1 25 | colorArray = ['red'] * N 26 | colorArray[0] = 'blue' 27 | colorArray[i:] = ['green'] * (N - i) 28 | displayArray(arr, colorArray, swapCount) 29 | time.sleep(max_time - (speedInput() * max_time / 100)) 30 | 31 | parent = 0 32 | while parent < i: 33 | indexes = (parent, 2 * parent + 1, 2 * parent + 2) 34 | _, highest = max( 35 | ((arr[index], index) for index in indexes if index < i), 36 | key=lambda x: x[0] 37 | ) 38 | if highest != parent: 39 | arr[highest], arr[parent] = arr[parent], arr[highest] 40 | swapCount += 1 41 | colorArray[parent] = 'blue' 42 | colorArray[highest] = 'yellow' 43 | displayArray(arr, colorArray, swapCount) 44 | time.sleep(max_time - (speedInput() * max_time / 100)) 45 | else: 46 | break 47 | parent = highest 48 | 49 | 50 | colorArray = ['green'] * N 51 | displayArray(arr, colorArray, swapCount) 52 | print("Sorted arr : ", arr) 53 | -------------------------------------------------------------------------------- /mainpage.py: -------------------------------------------------------------------------------- 1 | 2 | #---start import section------------------- 3 | import time 4 | import math 5 | import random 6 | 7 | from tkinter import Canvas, Frame, StringVar, Tk, Label, Button, Scale, HORIZONTAL 8 | from tkinter import ttk 9 | 10 | from mergesort import mergeSort 11 | from quicksort import quickSort 12 | from bubblesort import bubbleSort 13 | from selectionsort import selectionSort 14 | from heapsort import heapSort 15 | 16 | #---end import section--------------------- 17 | 18 | 19 | root = Tk() 20 | root.title('Sorting Algorithms Visualizer') 21 | root_width = 1000 22 | root_height = 650 23 | root.maxsize(root_width,root_height) #(width,height) 24 | root.config(bg='black') 25 | 26 | #----GLOBAL VARIABLES--------- 27 | allAlgos = ( 28 | 'Bubble Sort','Merge Sort','Quick Sort','Selection Sort', 'Heap Sort', 29 | ) 30 | selectedAlgo = StringVar() 31 | pauseBool = False 32 | arr = [] 33 | #----------------------------- 34 | 35 | def generateRandomArray(): 36 | #random array of non-repeating n elements 37 | global arr 38 | n = int(dataSize.get()) 39 | arr = list(range(1, n + 1)) 40 | random.shuffle(arr) 41 | 42 | arrayColor = ['red'] * n 43 | 44 | swapCount = 0 45 | displayArray(arr,arrayColor,swapCount) 46 | 47 | def normalizeArray(arr): 48 | m = max(arr) 49 | return [i / m for i in arr] 50 | 51 | def displayArray(arr,arrayColor,opCount): 52 | outputCanvas.delete('all') 53 | n = len(arr) 54 | 55 | outputCanvasHeight = 400 - 10 56 | outputCanvasWidth = 950 - 20 57 | 58 | barWidth = outputCanvasWidth/(n+1) 59 | barspace = 5 60 | initialspace = 10 61 | normalizedArr = normalizeArray(arr) 62 | 63 | for i,h in enumerate(normalizedArr): 64 | #top - left #|(x0,y0)-------------| 65 | x0 = i*barWidth+initialspace+barspace #| | 66 | y0 = outputCanvasHeight - h*350 #| | 67 | #| | 68 | #bottom-left #| | 69 | x1 = (i+1)*barWidth+initialspace #| | 70 | y1 = outputCanvasHeight #|-------------(x1,y1)| 71 | 72 | outputCanvas.create_rectangle(x0,y0,x1,y1, fill = arrayColor[i]) 73 | 74 | swapCountLabel = Label(outputCanvas,text = '#Swap Count : '+str(opCount),fg = 'white',bg = 'black',font = ('Comic Sans MS',12)) 75 | outputCanvas.create_window(80,20,window = swapCountLabel) 76 | 77 | root.update() 78 | 79 | # Map from string to sorting function 80 | lookup = { 81 | 'Bubble Sort': bubbleSort, 82 | 'Selection Sort': selectionSort, 83 | 'Merge Sort': mergeSort, 84 | 'Quick Sort': quickSort, 85 | 'Heap Sort': heapSort, 86 | } 87 | 88 | 89 | def startSort(): 90 | global arr 91 | fn = lookup[algoCombo.get()] 92 | fn(arr, displayArray, sortSpeed.get, pauseBool) 93 | 94 | 95 | #----User Interface Section--------------------------------------------------------------------------------------------- 96 | inputFrame = Frame(root,height = 200,width = 950,bg = 'black') 97 | inputFrame.grid(row = 0,column = 0,padx = 10,pady = 10) 98 | 99 | outputCanvas = Canvas(root,height = 400,width = 950,bg = '#99ffff') 100 | outputCanvas.grid(row = 1,column = 0,padx = 10,pady = 10) 101 | 102 | #--input frame------------------------------------------------------- 103 | head = Label(inputFrame,text = 'Select Algorithm -> ',fg = 'black',bg = '#ffff00',height = 1,width = 15,font = ('Comic Sans MS',14)) 104 | head.grid(row = 0,column = 0,padx = 5,pady = 5) 105 | 106 | algoCombo = ttk.Combobox(inputFrame,values = allAlgos,width = 15,font = ('Comic Sans MS',14)) 107 | algoCombo.grid(row = 0,column = 1,padx = 5,pady = 5) 108 | algoCombo.current() 109 | 110 | generate = Button(inputFrame,text = 'Generate',fg = 'black',bg = '#ff0000',height = 1,width = 10,font = ('Comic Sans MS',14),command = generateRandomArray ) 111 | generate.grid(row = 0,column = 2,padx = 5,pady = 5) 112 | 113 | dataSize = Scale(inputFrame,from_ = 3,to = 100,resolution = 1,length = 400,width = 15,orient = HORIZONTAL,label = 'Data Size [n]',font = ('Comic Sans MS',10)) 114 | dataSize.grid(row = 1,column = 0,padx = 5,pady = 5,columnspan = 2) 115 | 116 | sortSpeed = Scale(inputFrame,from_ = 1,to = 100,resolution = 0.1,length = 400,width = 15,orient = HORIZONTAL,label = 'Sorting Speed [s]',font = ('Comic Sans MS',10)) 117 | sortSpeed.grid(row = 2,column = 0,padx = 5,pady = 5,columnspan = 2) 118 | 119 | play = Button(inputFrame,text = 'Play',fg = 'black',bg = '#00ff00',height = 5,width = 10,font = ('Comic Sans MS',14),command = startSort ) 120 | play.grid(row = 1,column = 2,padx = 5,pady = 5,rowspan = 2) 121 | 122 | #--output frame------------------------------------------------------ 123 | 124 | root.mainloop() 125 | -------------------------------------------------------------------------------- /mergesort.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | max_time = 0.250 4 | swapCount = 0 5 | 6 | ##---to reset swap count 7 | def mergeSort(arr, displayArray, speedInput, pauseBool): 8 | global swapCount 9 | swapCount = 0 10 | start, end = 0, len(arr) - 1 11 | _merge_sort(arr, displayArray, speedInput, pauseBool, start, end) 12 | 13 | 14 | # divides the array recursively into two parts then sorts 15 | def _merge_sort(arr, displayArray, speedInput, pauseBool, start, end): 16 | if start < end: 17 | mid = (start + end) // 2 18 | _merge_sort(arr, displayArray, speedInput, pauseBool, start, mid) 19 | _merge_sort(arr, displayArray, speedInput, pauseBool, mid + 1, end) 20 | _merge(arr, displayArray, speedInput, pauseBool, start, mid, end) 21 | 22 | 23 | def _merge(arr, displayArray, speedInput, pauseBool, start, mid, end): 24 | global swapCount 25 | 26 | N = len(arr) 27 | #--highlight the left and the right parts of the array 28 | colorArray = ['red'] * N 29 | colorCoords = ((start, mid + 1, '#ffff00'), (mid + 1, end + 1, '#5200cc')) 30 | for lower, upper, color in colorCoords: 31 | colorArray[lower:upper] = [color] * (upper - lower) 32 | 33 | displayArray(arr, colorArray, swapCount) 34 | time.sleep(max_time - (speedInput() * max_time / 100)) 35 | 36 | arrL = arr[start:mid+1] 37 | arrR = arr[mid + 1:end + 1] 38 | 39 | i, j, k = 0, 0, start # i->arrL; j->arrR; k->arr 40 | 41 | while (i < len(arrL) and j < len(arrR)): 42 | if arrL[i] < arrR[j]: 43 | arr[k] = arrL[i] 44 | i += 1 45 | else: 46 | arr[k] = arrR[j] 47 | j += 1 48 | 49 | swapCount += 1 50 | colorArray[start:k] = ['green'] * (k - start) 51 | displayArray(arr, colorArray, swapCount) 52 | time.sleep(max_time - (speedInput() * max_time / 100)) 53 | 54 | k += 1 55 | 56 | #check if anything left 57 | while i < len(arrL): 58 | arr[k] = arrL[i] 59 | i += 1 60 | k += 1 61 | swapCount += 1 62 | colorArray[start:k] = ['green'] * (k - start) 63 | displayArray(arr, colorArray, swapCount) 64 | time.sleep(max_time - (speedInput() * max_time / 100)) 65 | 66 | while j < len(arrR): 67 | arr[k] = arrR[j] 68 | j += 1 69 | k += 1 70 | swapCount += 1 71 | colorArray[start:k] = ['green'] * (k - start) 72 | displayArray(arr, colorArray, swapCount) 73 | time.sleep(max_time - (speedInput() * max_time / 100)) 74 | 75 | print("Sorted arr : ", arr) 76 | -------------------------------------------------------------------------------- /quicksort.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | max_time = 0.250 4 | swapCount = 0 5 | 6 | 7 | def quickSort(arr, displayArray, speedInput, pauseBool): 8 | global swapCount 9 | swapCount = 0 10 | low, high = 0, len(arr) - 1 11 | _quick_sort(arr, displayArray, speedInput, pauseBool, low, high) 12 | 13 | 14 | def _quick_sort(arr, displayArray, speedInput, pauseBool, low, high): 15 | if low < high: 16 | #--partition index 17 | partInd = _partition(arr, displayArray, speedInput, pauseBool, low, high) 18 | 19 | _quick_sort(arr, displayArray, speedInput, pauseBool, low, partInd-1) 20 | _quick_sort(arr, displayArray, speedInput, pauseBool, partInd+1, high) 21 | 22 | 23 | ##--taking last element as pivot 24 | ##--separates smaller elements to the left and larger to the right 25 | def _partition(arr, displayArray, speedInput, pauseBool, low, high): 26 | global swapCount 27 | 28 | pointer = low 29 | count = high - low 30 | pivots = sorted( 31 | ((arr[low + i], low + i) for i in (0, count // 4, count // 2, 3 * count // 4, count)) 32 | ) 33 | # pivot = arr[high] 34 | pivot, pivot_pos = pivots[2] 35 | if pivot_pos != high: 36 | arr[pivot_pos], arr[high] = arr[high], arr[pivot_pos] 37 | swapCount += 1 38 | 39 | displayArray(arr, generateColorArray(low, high, pointer, pointer, len(arr), False), swapCount) 40 | time.sleep(max_time - (speedInput() * max_time / 100)) 41 | 42 | for j in range(low, high): 43 | 44 | if arr[j] < pivot: 45 | displayArray(arr, generateColorArray(low, high, pointer, j, len(arr), True), swapCount) 46 | time.sleep(max_time - (speedInput() * max_time / 100)) 47 | 48 | arr[j], arr[pointer] = arr[pointer], arr[j] 49 | pointer += 1 50 | swapCount += 1 51 | 52 | displayArray(arr, generateColorArray(low, high, pointer, j, len(arr), False), swapCount) 53 | time.sleep(max_time - (speedInput() * max_time / 100)) 54 | 55 | displayArray(arr, generateColorArray(low, high, pointer, high, len(arr), False), swapCount) 56 | time.sleep(max_time - (speedInput() * max_time / 100)) 57 | 58 | arr[high], arr[pointer] = arr[pointer], arr[high] 59 | swapCount += 1 60 | 61 | colorArray = ['green'] * len(arr) 62 | displayArray(arr, colorArray, swapCount) 63 | 64 | return pointer 65 | 66 | 67 | def generateColorArray(low, high, pointer, curr_ind, n, swapping): 68 | colorArray = ['#996633'] * n 69 | colorArray[low:high + 1] = ['yellow'] * (high - low + 1) 70 | colorArray[pointer] = 'black' 71 | colorArray[high] = 'red' 72 | colorArray[curr_ind] = 'blue' 73 | 74 | if swapping: 75 | colorArray[curr_ind] = 'green' 76 | colorArray[pointer] = 'green' 77 | return colorArray 78 | -------------------------------------------------------------------------------- /selectionsort.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | max_time = 0.250 4 | 5 | #finds the minimum value of the remaining array everytime 6 | def selectionSort(arr, displayArray, speedInput, pauseBool): 7 | swapCount = 0 8 | N = len(arr) 9 | for i in range(N): 10 | min_ind = i 11 | for j in range(i + 1, N): 12 | if arr[j] < arr[min_ind]: 13 | min_ind = j 14 | 15 | colorArray = ['red'] * N 16 | colorArray[:i] = ['green'] * i 17 | colorArray[j] = 'blue' 18 | colorArray[min_ind] = 'blue' 19 | 20 | displayArray(arr, colorArray, swapCount) 21 | time.sleep(max_time - (speedInput() * max_time / 100)) 22 | 23 | arr[i], arr[min_ind] = arr[min_ind], arr[i] 24 | swapCount += 1 25 | # colorArray = ['green' if x<=i else 'red' for x in range(len(arr))] 26 | colorArray = ['red'] * N 27 | colorArray[0:i + 1] = ['green'] * (i + 1) 28 | displayArray(arr, colorArray, swapCount) 29 | time.sleep(max_time - (speedInput() * max_time / 100)) 30 | 31 | colorArray = ['green'] * N 32 | displayArray(arr, colorArray, swapCount) 33 | print("Sorted arr : ", arr) 34 | --------------------------------------------------------------------------------