├── assets ├── js │ ├── Colors.js │ ├── RandomArrayGenerator.js │ ├── algorithms │ │ ├── SelectionSort.js │ │ ├── BubbleSort.js │ │ ├── InsertionSort.js │ │ ├── HeapSort.js │ │ ├── MergeSort.js │ │ └── QuickSort.js │ ├── Renderer.js │ └── index.js ├── font │ ├── norse-webfont.woff │ └── norse-webfont.woff2 └── css │ └── main.css ├── README.md └── index.html /assets/js/Colors.js: -------------------------------------------------------------------------------- 1 | const GREEN_COLOR = "green"; 2 | const RED_COLOR = "red"; 3 | const WHITE_COLOR = "white"; -------------------------------------------------------------------------------- /assets/font/norse-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OngDevTutorials/sorting-algorithms-visualizer/HEAD/assets/font/norse-webfont.woff -------------------------------------------------------------------------------- /assets/font/norse-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OngDevTutorials/sorting-algorithms-visualizer/HEAD/assets/font/norse-webfont.woff2 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sorting Algorithms Visualizer 2 | 3 | ### Link để vọc: 4 | https://ongdevtutorials.github.io/sorting-algorithms-visualizer/ 5 | 6 | ### Nếu các bạn thích những gì mình đang làm thì hãy ủng hộ mình nhé: 7 | 8 | https://unghotoi.com/ongdev 9 | -------------------------------------------------------------------------------- /assets/js/RandomArrayGenerator.js: -------------------------------------------------------------------------------- 1 | function generateRandomList(size) { 2 | var array = []; 3 | for (var i = 1; i <= size; i++) { 4 | array.push(i); 5 | } 6 | return shuffle(array); 7 | } 8 | 9 | function shuffle(array) { 10 | var currentIndex = array.length, 11 | temporaryValue, randomIndex; 12 | 13 | // While there remain elements to shuffle... 14 | while (0 !== currentIndex) { 15 | 16 | // Pick a remaining element... 17 | randomIndex = Math.floor(Math.random() * currentIndex); 18 | currentIndex -= 1; 19 | 20 | // And swap it with the current element. 21 | temporaryValue = array[currentIndex]; 22 | array[currentIndex] = array[randomIndex]; 23 | array[randomIndex] = temporaryValue; 24 | } 25 | 26 | return array; 27 | } -------------------------------------------------------------------------------- /assets/js/algorithms/SelectionSort.js: -------------------------------------------------------------------------------- 1 | async function doSelectionSort(array) { 2 | let size = array.length; 3 | let i, j; 4 | for (i = 0; i < size - 1; i++) { 5 | let minIndex = i; 6 | await changeBackgroundColor(array[minIndex], 'yellow'); 7 | for (j = i + 1; j < size; j++) { 8 | if (isStopTriggered) return; 9 | await changeBackgroundColor(array[j], 'red'); 10 | if (array[j] < array[minIndex]) { 11 | await changeBackgroundColor(array[minIndex], '#343a40'); 12 | minIndex = j; 13 | await changeBackgroundColor(array[minIndex], 'yellow'); 14 | } else { 15 | await changeBackgroundColor(array[j], '#343a40'); 16 | } 17 | } 18 | if (minIndex != i) { 19 | await swap(array[minIndex], array[i]); 20 | swapArrItem(array, minIndex, i); 21 | await endSwappingStep(array[minIndex], array[i]); 22 | } 23 | await changeBackgroundColor(array[minIndex], '#343a40'); 24 | } 25 | } -------------------------------------------------------------------------------- /assets/js/algorithms/BubbleSort.js: -------------------------------------------------------------------------------- 1 | async function doBubbleSort(array) { 2 | var length = array.length; 3 | for (var i = 0; i < length; i++) { 4 | for (var j = 0; j < length - 1; j++) { 5 | if (isStopTriggered) return; 6 | await prepareSwappingStep(array[j], array[j + 1]); 7 | if (array[j] > array[j + 1]) { 8 | swapArrItem(array, j, j + 1); 9 | await swap(array[j], array[j + 1]); 10 | } 11 | await endSwappingStep(array[j], array[j + 1]); 12 | } 13 | } 14 | return array; 15 | } 16 | 17 | async function doEnhancedBubbleSort(array) { 18 | var length = array.length; 19 | var isSwapped; 20 | var count = 1; 21 | do { 22 | isSwapped = false; 23 | for (var i = 0; i < length - count; i++) { 24 | if (isStopTriggered) return; 25 | await prepareSwappingStep(array[i], array[i + 1]); 26 | if (array[i] > array[i + 1]) { 27 | isSwapped = true; 28 | swapArrItem(array, i, i + 1); 29 | await swap(array[i], array[i + 1]); 30 | } 31 | await endSwappingStep(array[i], array[i + 1]); 32 | } 33 | count++; 34 | } 35 | while (isSwapped == true) 36 | return array; 37 | } -------------------------------------------------------------------------------- /assets/js/algorithms/InsertionSort.js: -------------------------------------------------------------------------------- 1 | async function doInsertionSort(array) { 2 | var length = array.length; 3 | for (var i = 1; i < length; i++) { 4 | var key = array[i]; 5 | var keyHeight = $(`#item-${key}`).height(); 6 | 7 | await changeBackgroundColor(array[i], 'red'); 8 | await changeHeightAndId(key, 0, 'key'); 9 | 10 | var j = i - 1; 11 | while (j >= 0) { 12 | if (isStopTriggered) return; 13 | if (array[j] > key) { 14 | await insert(array[j], 'key'); 15 | array[j + 1] = array[j]; 16 | j--; 17 | } else { 18 | break; 19 | } 20 | } 21 | array[j + 1] = key; 22 | 23 | await changeHeightAndId('key', keyHeight, key); 24 | await changeBackgroundColor(array[i], '#343a40'); 25 | } 26 | return array; 27 | } 28 | 29 | async function changeHeightAndId(id, height, newId) { 30 | return new Promise((resolve, reject) => { 31 | setTimeout(() => { 32 | $(`#item-${id}`).height(height); 33 | $(`#item-${id}`).prop('id', `item-${newId}`); 34 | resolve() 35 | }, window.delaySpeed); 36 | }); 37 | } 38 | 39 | async function insert(current, next) { 40 | return new Promise((resolve, reject) => { 41 | setTimeout(() => { 42 | console.log($(`#item-${current}`).height()); 43 | $(`#item-${next}`).height($(`#item-${current}`).height()); 44 | $(`#item-${current}`).height(0); 45 | 46 | var valTemp = $(`#item-${current}`).html(); 47 | if (valTemp != '' && valTemp != undefined && valTemp != null) { 48 | $(`#item-${current}`).html($(`#item-${next}`).html()); 49 | $(`#item-${next}`).html(valTemp); 50 | } 51 | 52 | $(`#item-${current}`).prop('id', 'current'); 53 | $(`#item-${next}`).prop('id', 'next'); 54 | $(`#current`).prop('id', `item-${next}`); 55 | $(`#next`).prop('id', `item-${current}`); 56 | 57 | resolve() 58 | }, window.delaySpeed); 59 | }); 60 | } -------------------------------------------------------------------------------- /assets/js/algorithms/HeapSort.js: -------------------------------------------------------------------------------- 1 | async function doHeapSort(array) { 2 | let length = array.length; 3 | let lastParentIndex = Math.floor(length / 2 - 1); 4 | while (lastParentIndex >= 0) { 5 | await heapify(array, length, lastParentIndex); 6 | lastParentIndex--; 7 | } 8 | 9 | for (let i = length - 1; i >= 0; i--) { 10 | if (isStopTriggered) return; 11 | await changeBackgroundColor(array[0], 'orange'); 12 | await changeBackgroundColor(array[i], 'red'); 13 | await swap(array[0], array[i]); 14 | swapArrItem(array, i, 0); 15 | await endSwappingStep(array[0], array[i]); 16 | await heapify(array, i, 0); 17 | } 18 | } 19 | 20 | async function heapify(array, length, index) { 21 | if (isStopTriggered) return; 22 | let largestIndex = lastLargestIndex = index; 23 | await changeBackgroundColor(array[largestIndex], 'orange'); 24 | let left = index * 2 + 1; 25 | let right = left + 1; 26 | await changeBackgroundColor(array[left], 'red'); 27 | await changeBackgroundColor(array[right], 'blue'); 28 | 29 | 30 | if (left < length && array[left] > array[largestIndex]) { 31 | 32 | largestIndex = left; 33 | 34 | } 35 | 36 | if (right < length && array[right] > array[largestIndex]) { 37 | // await changeBackgroundColor(array[largestIndex], '#343a40'); 38 | largestIndex = right; 39 | // await changeBackgroundColor(array[largestIndex], 'orange'); 40 | } 41 | await changeBackgroundColor(array[lastLargestIndex], '#343a40'); 42 | await changeBackgroundColor(array[largestIndex], 'orange'); 43 | if (largestIndex != index) { 44 | await swap(array[index], array[largestIndex]); 45 | swapArrItem(array, index, largestIndex); 46 | await resetHeapColor(array, index, left, right); 47 | await heapify(array, length, largestIndex); 48 | } else { 49 | await resetHeapColor(array, index, left, right); 50 | } 51 | 52 | } 53 | 54 | async function resetHeapColor(array, index, left, right) { 55 | await changeBackgroundColor(array[index], '#343a40'); 56 | await changeBackgroundColor(array[left], '#343a40'); 57 | await changeBackgroundColor(array[right], '#343a40'); 58 | } -------------------------------------------------------------------------------- /assets/js/algorithms/MergeSort.js: -------------------------------------------------------------------------------- 1 | async function doMergeSort(array) { 2 | await mergeSort(array, array, 0); 3 | } 4 | 5 | async function mergeSort(originalArray, array, startIndex) { 6 | if (isStopTriggered) return; 7 | if (array.length < 2) { 8 | return array; 9 | } 10 | var middle = Math.floor(array.length / 2); 11 | var leftArray = array.slice(0, middle); 12 | var rightArray = array.slice(middle, array.length); 13 | 14 | var leftSortedArray = await mergeSort(originalArray, leftArray, startIndex); 15 | var rightSortedArray = await mergeSort(originalArray, rightArray, startIndex + leftSortedArray.length); 16 | 17 | return mergeSortedArrays(originalArray, leftSortedArray, rightSortedArray, startIndex); 18 | } 19 | 20 | async function mergeSortedArrays(originalArray, leftSortedArray, rightSortedArray, startIndex) { 21 | var sortedArray = [], 22 | leftArrIndex = 0, 23 | rightArrIndex = 0; 24 | 25 | while (leftArrIndex < leftSortedArray.length && rightArrIndex < rightSortedArray.length) { 26 | let leftMinValue = leftSortedArray[leftArrIndex], 27 | rightMinValue = rightSortedArray[rightArrIndex], 28 | minimumValue = 0; 29 | await changeBackgroundColor(leftMinValue, 'green'); 30 | await changeBackgroundColor(rightMinValue, 'green'); 31 | if (leftMinValue <= rightMinValue) { 32 | minimumValue = leftMinValue; 33 | leftArrIndex++; 34 | } else { 35 | minimumValue = rightMinValue; 36 | rightArrIndex++; 37 | } 38 | 39 | sortedArray.push(minimumValue); 40 | await changeBackgroundColor(leftMinValue, window.baseColor); 41 | await changeBackgroundColor(rightMinValue, window.baseColor); 42 | } 43 | 44 | if (leftArrIndex < leftSortedArray.length) { 45 | sortedArray = sortedArray.concat(leftSortedArray.slice(leftArrIndex)); 46 | } 47 | 48 | if (rightArrIndex < rightSortedArray.length) { 49 | sortedArray = sortedArray.concat(rightSortedArray.slice(rightArrIndex)); 50 | } 51 | 52 | originalArray.splice(startIndex, sortedArray.length, ...sortedArray); 53 | await renderList(originalArray); 54 | 55 | return sortedArray; 56 | } -------------------------------------------------------------------------------- /assets/css/main.css: -------------------------------------------------------------------------------- 1 | /*! Generated by Font Squirrel (https://www.fontsquirrel.com) on September 14, 2019 */ 2 | 3 | @font-face { 4 | font-family: 'norseregular'; 5 | src: url('../font/norse-webfont.woff2') format('woff2'), url('../font/norse-webfont.woff2') format('woff'); 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | html, 11 | body { 12 | font-family: 'norseregular'; 13 | color: 'white'; 14 | } 15 | 16 | .flex-column-container { 17 | display: flex; 18 | flex-direction: column; 19 | justify-content: center; 20 | align-items: center; 21 | } 22 | 23 | .flex-row-container { 24 | display: flex; 25 | flex-direction: row; 26 | justify-content: center; 27 | align-items: center; 28 | } 29 | 30 | 31 | /* Custom slider */ 32 | 33 | .slider { 34 | -webkit-appearance: none; 35 | height: 3px; 36 | background: #d3d3d3; 37 | outline: none; 38 | opacity: 0.7; 39 | -webkit-transition: .2s; 40 | transition: opacity .2s; 41 | } 42 | 43 | .slider:hover { 44 | opacity: 1; 45 | } 46 | 47 | .slider::-webkit-slider-thumb { 48 | -webkit-appearance: none; 49 | appearance: none; 50 | width: 15px; 51 | height: 15px; 52 | background: #4CAF50; 53 | border-radius: 50%; 54 | cursor: pointer; 55 | } 56 | 57 | .slider::-moz-range-thumb { 58 | width: 15px; 59 | height: 15px; 60 | border-radius: 50%; 61 | background: #4CAF50; 62 | cursor: pointer; 63 | } 64 | 65 | 66 | /* End slider */ 67 | 68 | 69 | /* General styles */ 70 | 71 | .white-text { 72 | color: white; 73 | } 74 | 75 | .large-height { 76 | height: 32px; 77 | } 78 | 79 | .nav-item { 80 | padding: 0 10px; 81 | } 82 | 83 | .border-right { 84 | border-right: 1px solid white; 85 | } 86 | 87 | button { 88 | height: 32px; 89 | padding-top: 4px !important; 90 | } 91 | 92 | #list-container { 93 | margin: 20px auto; 94 | height: 650px; 95 | display: flex; 96 | flex-direction: row; 97 | justify-content: flex-start; 98 | align-items: flex-end; 99 | border-bottom: 5px solid black; 100 | } 101 | 102 | #list-container div { 103 | flex-grow: 1; 104 | flex-shrink: 1; 105 | background-color: #343a40; 106 | text-align: center; 107 | color: white; 108 | } 109 | 110 | #algo-info span { 111 | font-size: 20px; 112 | } -------------------------------------------------------------------------------- /assets/js/Renderer.js: -------------------------------------------------------------------------------- 1 | var listContainer = document.getElementById('list-container'); 2 | var listDisplayer = document.getElementById('list-displayer'); 3 | 4 | async function renderList(list) { 5 | return new Promise((resolve, reject) => { 6 | setTimeout(() => { 7 | listContainer.innerHTML = ""; 8 | var size = list.length; 9 | window.rateToFillContainer = (listContainer.clientHeight - 20) / list.length; 10 | var newUlContent = ""; 11 | list.forEach(item => { 12 | newUlContent += `