├── README.md ├── assets ├── bubble-sort.js ├── favicon.ico ├── heapsort.js ├── insertion-sort.js ├── merge-sort.js ├── quicksort.js ├── script.js ├── selection-sort.js └── style.css └── index.html /README.md: -------------------------------------------------------------------------------- 1 | # Sorting Visualizer 2 | 3 | **A static website for visualizing different comparison based sorting algorithms.** 4 | 5 | [Website Link](https://mahfuzrifat7.github.io/SortingVisualizer "Sorting Visualizer") -------------------------------------------------------------------------------- /assets/bubble-sort.js: -------------------------------------------------------------------------------- 1 | async function bubbleSort() { 2 | var i, j; 3 | await sleep(delay); 4 | 5 | for(i = 0; i < size - 1; i++) { 6 | for(j = 0; j < size - i - 1; j++) { 7 | await sleep(delay); 8 | 9 | setColor(j, COMPARE); 10 | setColor(j + 1, COMPARE); 11 | await sleep(delay); 12 | 13 | if(arr[j] > arr[j + 1]) { 14 | swap(j, j + 1); 15 | await sleep(delay); 16 | } 17 | 18 | setColor(j, UNSORTED); 19 | setColor(j + 1, UNSORTED); 20 | } 21 | 22 | await sleep(delay); 23 | 24 | setColor(j, SORTED); 25 | } 26 | 27 | setColor(0, SORTED); 28 | } 29 | -------------------------------------------------------------------------------- /assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahfuzrifat7/SortingVisualizer/605efa880cdf978c182876bef97f74c27c5f1450/assets/favicon.ico -------------------------------------------------------------------------------- /assets/heapsort.js: -------------------------------------------------------------------------------- 1 | var heapSize; 2 | 3 | function left(i) { 4 | return 2 * i + 1; 5 | } 6 | 7 | function right(i) { 8 | return 2 * i + 2; 9 | } 10 | 11 | async function maxHeapify(i) { 12 | var l = left(i); 13 | var r = right(i); 14 | var largest, temp; 15 | 16 | setColor(i, COMPARE); 17 | if(l < heapSize) 18 | setColor(l, LEFT); 19 | if(r < heapSize) 20 | setColor(r, RIGHT); 21 | 22 | await sleep(delay); 23 | 24 | if(l < heapSize && arr[l] > arr[i]) 25 | largest = l; 26 | else 27 | largest = i; 28 | 29 | if(r < heapSize && arr[r] > arr[largest]) 30 | largest = r; 31 | 32 | if(l < heapSize) 33 | setColor(l, UNSORTED); 34 | if(r < heapSize) 35 | setColor(r, UNSORTED); 36 | setColor(largest, SELECTED); 37 | 38 | await sleep(delay); 39 | 40 | if(largest != i) { 41 | swap(i, largest); 42 | setColor(largest, COMPARE); 43 | setColor(i, SELECTED); 44 | await sleep(delay); 45 | 46 | setColor(largest, UNSORTED); 47 | setColor(i, UNSORTED); 48 | 49 | await maxHeapify(largest); 50 | } 51 | else 52 | setColor(i, UNSORTED); 53 | } 54 | 55 | async function buildMaxHeap() { 56 | heapSize = size; 57 | 58 | for(var i = Math.floor(size / 2) - 1; i >= 0; i--) 59 | await maxHeapify(i); 60 | } 61 | 62 | async function heapsort() { 63 | await sleep(delay); 64 | 65 | await buildMaxHeap(); 66 | 67 | for(var i = size - 1; i > 0; i--) { 68 | setColor(0, SELECTED); 69 | setColor(i, COMPARE); 70 | await sleep(delay); 71 | 72 | setColor(0, COMPARE); 73 | setColor(i, SELECTED); 74 | swap(0, i); 75 | heapSize--; 76 | await sleep(delay); 77 | 78 | setColor(i, SORTED); 79 | 80 | await maxHeapify(0); 81 | } 82 | 83 | setColor(0, SORTED); 84 | } 85 | -------------------------------------------------------------------------------- /assets/insertion-sort.js: -------------------------------------------------------------------------------- 1 | async function insertionSort() { 2 | var i, j, key; 3 | await sleep(delay); 4 | 5 | setColor(0, SELECTED); 6 | await sleep(delay); 7 | 8 | setColor(0, SORTED); 9 | 10 | for(i = 1; i < size; i++) { 11 | await sleep(delay); 12 | 13 | setColor(i, SELECTED); 14 | await sleep(delay); 15 | 16 | j = i - 1; 17 | key = arr[i]; 18 | 19 | while(j >= 0 && arr[j] > key) { 20 | setColor(j, COMPARE); 21 | await sleep(delay); 22 | 23 | swap(j, j + 1); 24 | setColor(j, SELECTED); 25 | setColor(j + 1, COMPARE); 26 | await sleep(delay); 27 | 28 | setColor(j + 1, SORTED); 29 | await sleep(delay); 30 | 31 | j--; 32 | } 33 | 34 | setColor(j + 1, SORTED); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /assets/merge-sort.js: -------------------------------------------------------------------------------- 1 | async function merge(p, q, r) { 2 | await sleep(delay); 3 | 4 | var i, j; 5 | var n1 = q - p + 1; 6 | var n2 = r - q; 7 | var L = []; 8 | var R = []; 9 | 10 | for(i = 0; i < n1; i++) { 11 | L.push(arr[p + i]); 12 | setColor(p + i, LEFT); 13 | } 14 | for(j = 0; j < n2; j++) { 15 | R.push(arr[q + j + 1]); 16 | setColor(q + j + 1, RIGHT); 17 | } 18 | 19 | L.push(Infinity); 20 | R.push(Infinity); 21 | 22 | i = 0; 23 | j = 0; 24 | 25 | for(var k = p; k <= r; k++) { 26 | await sleep(delay); 27 | 28 | if(L[i] <= R[j]) { 29 | arr[k] = L[i]; 30 | i++; 31 | } 32 | else { 33 | arr[k] = R[j]; 34 | j++; 35 | } 36 | 37 | setHeight(k, arr[k]); 38 | setColor(k, SELECTED); 39 | } 40 | 41 | await sleep(delay); 42 | 43 | if(p == 0 && r == size - 1) 44 | setColorRange(p, r, SORTED); 45 | else 46 | setColorRange(p, r, UNSORTED); 47 | } 48 | 49 | async function mergeSort(p, r) { 50 | if(p < r) { 51 | var q = Math.floor( (p + r) / 2 ); 52 | 53 | await mergeSort(p, q); 54 | 55 | await mergeSort(q + 1, r); 56 | 57 | await merge(p, q, r); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /assets/quicksort.js: -------------------------------------------------------------------------------- 1 | async function partition(p, r) { 2 | await sleep(delay); 3 | 4 | var i = p - 1; 5 | setColor(r, SELECTED); 6 | 7 | for(var j = p; j < r; j++) { 8 | await sleep(delay); 9 | 10 | if(arr[j] <= arr[r]) { 11 | i++; 12 | swap(i, j); 13 | setColor(j, RIGHT); 14 | setColor(i, LEFT); 15 | } 16 | else 17 | setColor(j, RIGHT); 18 | } 19 | 20 | if(i + 1 < r) { 21 | await sleep(delay); 22 | 23 | swap(i + 1, r); 24 | setColor(r, RIGHT); 25 | setColor(i + 1, SELECTED); 26 | } 27 | 28 | await sleep(delay); 29 | 30 | setColorRange(p, r, UNSORTED); 31 | 32 | return i + 1; 33 | } 34 | 35 | async function quicksort(p, r) { 36 | if(p < r) { 37 | var q = await partition(p, r); 38 | 39 | await quicksort(p, q - 1); 40 | 41 | setColorRange(p, q, SORTED); 42 | await quicksort(q + 1, r); 43 | 44 | setColorRange(q + 1, r, SORTED); 45 | } 46 | 47 | if(p == 0 && r == size - 1) 48 | await sleep(delay); 49 | } 50 | -------------------------------------------------------------------------------- /assets/script.js: -------------------------------------------------------------------------------- 1 | const MIN_SIZE = 4; 2 | const MAX_SIZE = 64; 3 | const DEFAULT_SIZE = 32; 4 | 5 | const MIN_SPEED = 1; 6 | const MAX_SPEED = 4; 7 | const DEFAULT_SPEED = 3; 8 | 9 | const MIN = 20; 10 | const MAX = 300; 11 | 12 | const WAITING_TIME = 100; 13 | 14 | const UNSORTED = 'deepskyblue'; 15 | const SORTED = 'mediumspringgreen'; 16 | const COMPARE = 'crimson'; 17 | const SELECTED = 'blueviolet'; 18 | const LEFT = 'gold'; 19 | const RIGHT = 'orangered'; 20 | 21 | var size; 22 | var delay; 23 | 24 | var arr = []; 25 | 26 | var array_container_width; 27 | var element_width; 28 | var element_width_max; 29 | var margin_element; 30 | 31 | var algo_selected; 32 | 33 | function updateValues() { 34 | array_container_width = Math.floor( $("#array-container").width() ); 35 | element_width_max = Math.floor(array_container_width / 20); 36 | 37 | margin_element = 2; 38 | if( parseInt( $(window).width() ) < 1200 ) 39 | margin_element = 1; 40 | } 41 | 42 | function findElementWidth() { 43 | element_width = Math.floor(array_container_width / size); 44 | element_width -= 2 * margin_element; 45 | 46 | if(element_width > element_width_max) 47 | element_width = element_width_max; 48 | } 49 | 50 | function createArray() { 51 | arr = []; 52 | $("#array").html(''); 53 | 54 | for(var i = 0; i < size; i++) { 55 | var n = Math.floor( Math.random() * (MAX - MIN + 1) ) + MIN; 56 | arr.push(n); 57 | 58 | var $element = $('
'); 59 | $element.attr('id', "e" + i); 60 | $element.attr('class', "element"); 61 | $element.css('background-color', UNSORTED); 62 | $element.css('width', element_width.toString() + 'px'); 63 | $element.css('height', n.toString() + 'px'); 64 | $element.css('margin-left', margin_element + 'px'); 65 | $element.css('margin-right', margin_element + 'px'); 66 | $element.appendTo("#array"); 67 | } 68 | } 69 | 70 | function setHeight(id, height) { 71 | $("#e" + id).css('height', height); 72 | } 73 | 74 | function setColor(id, color) { 75 | $("#e" + id).css('background-color', color); 76 | } 77 | 78 | function setColorRange(p, r, color) { 79 | for(var i = p; i <= r; i++) 80 | $("#e" + i).css('background-color', color); 81 | } 82 | 83 | function swap(a, b) { 84 | var temp = arr[a]; 85 | arr[a] = arr[b]; 86 | arr[b] = temp; 87 | 88 | var h1 = $("#e" + a).css('height'); 89 | var h2 = $("#e" + b).css('height'); 90 | 91 | setHeight(a, h2); 92 | setHeight(b, h1); 93 | } 94 | 95 | function disableOthers() { 96 | $("#sort").prop('disabled', true); 97 | $("#randomize").prop('disabled', true); 98 | $("#size-slider").prop('disabled', true); 99 | } 100 | 101 | function enableOthers() { 102 | $("#sort").prop('disabled', false); 103 | $("#randomize").prop('disabled', false); 104 | $("#size-slider").prop('disabled', false); 105 | } 106 | 107 | function sleep(ms) { 108 | return new Promise(resolve => setTimeout(resolve, ms)); 109 | } 110 | 111 | $(document).ready(function() { 112 | $("#size-slider").attr('min', MIN_SIZE); 113 | $("#size-slider").attr('max', MAX_SIZE); 114 | $("#size-slider").attr('value', DEFAULT_SIZE); 115 | 116 | $("#speed-slider").attr('min', MIN_SPEED); 117 | $("#speed-slider").attr('max', MAX_SPEED); 118 | $("#speed-slider").attr('value', DEFAULT_SPEED); 119 | 120 | size = DEFAULT_SIZE; 121 | delay = WAITING_TIME * Math.pow(2, MAX_SPEED - DEFAULT_SPEED); 122 | 123 | updateValues(); 124 | 125 | findElementWidth(); 126 | createArray(); 127 | 128 | $("#randomize").click( 129 | function() { 130 | createArray(); 131 | } 132 | ); 133 | 134 | $(".algo-btn").click( 135 | function() { 136 | algo_selected = $(this).html(); 137 | 138 | $(".algo-btn-active").removeClass('algo-btn-active'); 139 | $(this).addClass('algo-btn-active'); 140 | 141 | $("#no-algo-warning").removeClass('display-flex'); 142 | $("#no-algo-warning").addClass('display-none'); 143 | } 144 | ); 145 | 146 | $("#sort").click( 147 | async function() { 148 | disableOthers(); 149 | 150 | setColorRange(0, size - 1, UNSORTED); 151 | 152 | if(algo_selected == "Bubble Sort") 153 | await bubbleSort(); 154 | else if(algo_selected == "Selection Sort") 155 | await selectionSort(); 156 | else if(algo_selected == "Insertion Sort") 157 | await insertionSort(); 158 | else if(algo_selected == "Merge Sort") 159 | await mergeSort(0, size - 1); 160 | else if(algo_selected == "Quicksort") 161 | await quicksort(0, size - 1); 162 | else if(algo_selected == "Heapsort") 163 | await heapsort(); 164 | else { 165 | $("#no-algo-warning").removeClass('display-none'); 166 | $("#no-algo-warning").addClass('display-flex'); 167 | } 168 | 169 | enableOthers(); 170 | } 171 | ); 172 | 173 | $("#size-slider").on('input', function() { 174 | size = $(this).val(); 175 | 176 | findElementWidth(); 177 | createArray(); 178 | }); 179 | 180 | $("#speed-slider").on('input', function() { 181 | delay = WAITING_TIME * Math.pow(2, MAX_SPEED - $(this).val()); 182 | }); 183 | 184 | $(window).resize(function() { 185 | if(array_container_width != Math.floor( $("#array-container").width() )) { 186 | updateValues(); 187 | 188 | findElementWidth(); 189 | 190 | for(var i = 0; i < size; i++) { 191 | $("#e" + i).css('width', element_width.toString() + 'px'); 192 | $("#e" + i).css('margin-left', margin_element + 'px'); 193 | $("#e" + i).css('margin-right', margin_element + 'px'); 194 | } 195 | } 196 | }); 197 | }); 198 | -------------------------------------------------------------------------------- /assets/selection-sort.js: -------------------------------------------------------------------------------- 1 | async function selectionSort() { 2 | var i, j, min_idx; 3 | 4 | for(i = 0; i < size - 1; i++) { 5 | await sleep(delay); 6 | 7 | min_idx = i; 8 | setColor(min_idx, SELECTED); 9 | 10 | for(j = i + 1; j < size; j++) { 11 | await sleep(delay); 12 | 13 | setColor(j, COMPARE); 14 | 15 | await sleep(delay); 16 | 17 | if(arr[j] < arr[min_idx]) { 18 | setColor(min_idx, UNSORTED); 19 | min_idx = j; 20 | setColor(min_idx, SELECTED); 21 | await sleep(delay); 22 | } 23 | else 24 | setColor(j, UNSORTED); 25 | } 26 | 27 | await sleep(delay); 28 | 29 | if(min_idx != i) { 30 | setColor(i, COMPARE); 31 | await sleep(delay); 32 | 33 | setColor(min_idx, COMPARE); 34 | setColor(i, SELECTED); 35 | swap(min_idx, i); 36 | await sleep(delay); 37 | } 38 | 39 | setColor(min_idx, UNSORTED); 40 | setColor(i, SORTED); 41 | } 42 | 43 | setColor(size - 1, SORTED); 44 | } 45 | -------------------------------------------------------------------------------- /assets/style.css: -------------------------------------------------------------------------------- 1 | *:focus, button:focus { 2 | outline: none; 3 | } 4 | 5 | body { 6 | background-color: black; 7 | font-family: "Catamaran", sans-serif; 8 | color: #ccc; 9 | } 10 | 11 | .display-none { 12 | display: none; 13 | } 14 | 15 | .display-flex { 16 | display: flex; 17 | } 18 | 19 | #array-container { 20 | height: 350px; 21 | margin-top: 3em; 22 | display: flex; 23 | flex-direction: column-reverse; 24 | position: relative; 25 | } 26 | 27 | #array { 28 | margin: 1em auto; 29 | } 30 | 31 | .element { 32 | display: inline-block; 33 | border-radius: 5px; 34 | } 35 | 36 | #no-algo-warning { 37 | position: absolute; 38 | justify-content: center; 39 | align-items: center; 40 | top: 0; 41 | bottom: 0; 42 | left: 0; 43 | right: 0; 44 | margin: auto; 45 | width: 250px; 46 | height: 50px; 47 | text-align: center; 48 | background-color: rgba(0, 0, 0, 0.8); 49 | border: 1px solid #ccc; 50 | border-radius: 5px; 51 | } 52 | 53 | #algo-container { 54 | max-width: 1000px; 55 | margin: 1em auto; 56 | } 57 | 58 | .algo-btn, #sort, #randomize { 59 | background-color: #222; 60 | margin: 5px 2px; 61 | padding: 5px 20px; 62 | color: #ccc; 63 | font-size: 1.2em; 64 | border: none; 65 | border-radius: 50px; 66 | } 67 | 68 | .algo-btn:hover, .algo-btn-active { 69 | background-color: #ccc; 70 | color: #222; 71 | } 72 | 73 | #sort { 74 | float: right; 75 | background-color: mediumspringgreen; 76 | color: black; 77 | } 78 | 79 | #sort:hover, #randomize:hover { 80 | opacity: 0.8; 81 | } 82 | 83 | #sort:disabled, #randomize:disabled { 84 | opacity: 0.5; 85 | cursor: not-allowed; 86 | } 87 | 88 | #change-container { 89 | max-width: 500px; 90 | margin: 1em auto; 91 | } 92 | 93 | #randomize, .slider-container { 94 | vertical-align: middle; 95 | } 96 | 97 | #randomize { 98 | background-color: crimson; 99 | color: #ddd; 100 | } 101 | 102 | #sliders { 103 | float: right; 104 | } 105 | 106 | .slider-container { 107 | display: inline-block; 108 | margin-left: 20px; 109 | } 110 | 111 | .slider-container label { 112 | display: block; 113 | margin: 0; 114 | text-align: center; 115 | font-size: 1.2em; 116 | } 117 | 118 | .slider { 119 | -webkit-appearance: none; 120 | width: 130px; 121 | height: 15px; 122 | background-color: transparent; 123 | } 124 | 125 | .slider::-webkit-slider-runnable-track { 126 | -webkit-appearance: none; 127 | height: 5px; 128 | background-color: #ccc; 129 | border-radius: 5px; 130 | cursor: pointer; 131 | } 132 | 133 | .slider::-moz-range-track { 134 | height: 5px; 135 | background-color: #ccc; 136 | border-radius: 5px; 137 | cursor: pointer; 138 | } 139 | 140 | .slider::-moz-range-progress { 141 | height: 5px; 142 | background-color: #777; 143 | border-radius: 5px; 144 | cursor: pointer; 145 | } 146 | 147 | .slider::-webkit-slider-thumb { 148 | -webkit-appearance: none; 149 | background-color: #222; 150 | border: 2px solid #ccc; 151 | width: 15px; 152 | height: 15px; 153 | border-radius: 15px; 154 | margin-top: -5px; 155 | } 156 | 157 | .slider::-moz-range-thumb { 158 | background-color: #222; 159 | border: 2px solid #ccc; 160 | width: 13px; 161 | height: 13px; 162 | border-radius: 13px; 163 | cursor: pointer; 164 | } 165 | 166 | .slider:disabled { 167 | opacity: 0.5; 168 | } 169 | 170 | .slider:disabled::-webkit-slider-runnable-track { 171 | cursor: not-allowed; 172 | } 173 | 174 | .slider:disabled::-moz-range-track { 175 | cursor: not-allowed; 176 | } 177 | 178 | .slider:disabled::-moz-range-progress { 179 | cursor: not-allowed; 180 | } 181 | 182 | .slider:disabled::-moz-range-thumb { 183 | cursor: not-allowed; 184 | } 185 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Sorting Visualizer 13 | 14 | 15 |
16 |
17 |
18 | 19 |
20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 | 31 |
32 |
33 | 34 | 35 |
36 |
37 | 38 | 39 |
40 |
41 |
42 |
43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | --------------------------------------------------------------------------------