├── public ├── robots.txt ├── favicon.ico ├── logo192.png ├── logo512.png ├── manifest.json └── index.html ├── src ├── components │ ├── sounds │ │ ├── sound1.wav │ │ └── sound2.wav │ ├── assets │ │ ├── Button.js │ │ ├── Toggle.js │ │ ├── Dropdown.js │ │ └── Slider.js │ ├── styles │ │ ├── dropdown.css │ │ ├── visualizer.css │ │ ├── button.css │ │ ├── toggle.css │ │ └── slider.css │ └── Visualizer.js ├── App.js ├── setupTests.js ├── App.test.js ├── App.css ├── index.css ├── reportWebVitals.js └── index.js ├── .gitignore ├── package.json └── README.md /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harsh-solanki21/sorting-visualizer/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harsh-solanki21/sorting-visualizer/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harsh-solanki21/sorting-visualizer/HEAD/public/logo512.png -------------------------------------------------------------------------------- /src/components/sounds/sound1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harsh-solanki21/sorting-visualizer/HEAD/src/components/sounds/sound1.wav -------------------------------------------------------------------------------- /src/components/sounds/sound2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harsh-solanki21/sorting-visualizer/HEAD/src/components/sounds/sound2.wav -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './App.css' 3 | import Visualizer from './components/Visualizer' 4 | 5 | function App() { 6 | return ( 7 | <> 8 | 9 | 10 | ) 11 | } 12 | 13 | export default App 14 | -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /src/components/assets/Button.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Button = ({ type, name, onClick, disabled }) => { 4 | return ( 5 | 12 | ) 13 | } 14 | 15 | export default Button 16 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | background-color: #f1f1f1; 6 | } 7 | 8 | @import url('./components/styles/button.css'); 9 | 10 | @import url('./components/styles/dropdown.css'); 11 | 12 | @import url('./components/styles/slider.css'); 13 | 14 | @import url('./components/styles/toggle.css'); 15 | 16 | @import url('./components/styles/visualizer.css'); 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /src/components/styles/dropdown.css: -------------------------------------------------------------------------------- 1 | .dropdown { 2 | background-color: white; 3 | border: 2px solid dodgerblue; 4 | border-radius: 5px; 5 | width: 10%; 6 | } 7 | .dropdown select:hover { 8 | cursor: pointer; 9 | } 10 | .dropdown select { 11 | font-size: 1rem; 12 | font-weight: normal; 13 | padding: 10px 15px 10px 2px; 14 | border: none; 15 | background-color: transparent; 16 | } 17 | .dropdown select:focus { 18 | outline: none; 19 | } 20 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import './index.css' 4 | import App from './App' 5 | import reportWebVitals from './reportWebVitals' 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ) 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals() 18 | -------------------------------------------------------------------------------- /src/components/assets/Toggle.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Toggle = ({ context, soundState, onChange, disabled }) => { 4 | return ( 5 |
6 | {context} 7 |
8 | 12 | {soundState} 13 |
14 |
15 | ) 16 | } 17 | 18 | export default Toggle 19 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /src/components/assets/Dropdown.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Dropdown = ({ onChange, disabled }) => { 4 | return ( 5 |
6 | 14 |
15 | ) 16 | } 17 | 18 | export default Dropdown 19 | -------------------------------------------------------------------------------- /src/components/styles/visualizer.css: -------------------------------------------------------------------------------- 1 | .header { 2 | position: relative; 3 | padding: 0 25px; 4 | display: flex; 5 | flex-direction: row; 6 | align-items: center; 7 | justify-content: center; 8 | justify-content: space-between; 9 | background-color: aqua; 10 | } 11 | 12 | .sortingBars { 13 | position: absolute; 14 | top: 25%; 15 | left: 5%; 16 | } 17 | 18 | .bars { 19 | width: 10px; 20 | background-color: #ff7f50; 21 | margin-left: 4px; 22 | display: inline-block; 23 | border-radius: 10px; 24 | } 25 | 26 | .algoInfo { 27 | position: absolute; 28 | bottom: 30px; 29 | left: 5%; 30 | width: 90%; 31 | height: 70px; 32 | border: 3px solid #6495ed; 33 | border-radius: 5px; 34 | display: flex; 35 | justify-content: center; 36 | align-items: center; 37 | } 38 | 39 | .algoInfo div { 40 | margin-left: 30px; 41 | color: #ff581c; 42 | font-size: 25px; 43 | font-weight: 800; 44 | } 45 | -------------------------------------------------------------------------------- /src/components/styles/button.css: -------------------------------------------------------------------------------- 1 | .button { 2 | color: white; 3 | border: none; 4 | font-size: 1rem; 5 | font-weight: 600; 6 | padding: 12px 15px; 7 | text-align: center; 8 | cursor: pointer; 9 | outline: none; 10 | border-radius: 5px; 11 | } 12 | 13 | .sort { 14 | background-color: #ea4c89; 15 | box-shadow: 0 2px #f082ac; 16 | } 17 | 18 | .sort:hover { 19 | background-color: #e7387b; 20 | box-shadow: 0 12px 16px 0 rgba(0, 0, 0, 0.24), 21 | 0 17px 50px 0 rgba(0, 0, 0, 0.19); 22 | } 23 | 24 | .sort:active { 25 | box-shadow: 0 2px #f082ac; 26 | transform: translateY(2px); 27 | } 28 | 29 | .newArray { 30 | background-color: dodgerblue; 31 | box-shadow: 0 2px powderblue; 32 | } 33 | 34 | .newArray:hover { 35 | background-color: #2a75ff; 36 | box-shadow: 0 12px 16px 0 rgba(0, 0, 0, 0.24), 37 | 0 17px 50px 0 rgba(0, 0, 0, 0.19); 38 | } 39 | 40 | .button:active { 41 | box-shadow: 0 2px powderblue; 42 | transform: translateY(2px); 43 | } 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sorting-visualizer", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.2", 7 | "@testing-library/react": "^12.1.4", 8 | "@testing-library/user-event": "^13.5.0", 9 | "react": "^17.0.2", 10 | "react-dom": "^17.0.2", 11 | "react-scripts": "5.0.0", 12 | "react-toggle": "^4.1.2", 13 | "use-sound": "^4.0.1", 14 | "web-vitals": "^2.1.4" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test", 20 | "eject": "react-scripts eject" 21 | }, 22 | "eslintConfig": { 23 | "extends": [ 24 | "react-app", 25 | "react-app/jest" 26 | ] 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/components/assets/Slider.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Slider = ({ onChange, disabled }) => { 4 | return ( 5 |
6 |
7 |
Select Speed
8 |
9 | 16 | 17 | 25 | 26 | 33 | 34 |
35 |
36 |
37 |
38 | ) 39 | } 40 | 41 | export default Slider 42 | -------------------------------------------------------------------------------- /src/components/styles/toggle.css: -------------------------------------------------------------------------------- 1 | .toggle { 2 | text-align: center; 3 | } 4 | 5 | .context { 6 | float: left; 7 | padding-left: 7px; 8 | font-size: 1.1rem; 9 | font-weight: 400; 10 | } 11 | 12 | .sound-state { 13 | padding-left: 4px; 14 | } 15 | 16 | .toggle-switch { 17 | position: relative; 18 | display: inline-block; 19 | width: 60px; 20 | height: 34px; 21 | } 22 | 23 | .toggle-switch input { 24 | opacity: 0; 25 | width: 0; 26 | height: 0; 27 | } 28 | 29 | .slider { 30 | position: absolute; 31 | cursor: pointer; 32 | top: 0; 33 | left: 0; 34 | right: 0; 35 | bottom: 0; 36 | background-color: #ccc; 37 | -webkit-transition: 0.4s; 38 | transition: 0.4s; 39 | } 40 | 41 | .slider:before { 42 | position: absolute; 43 | content: ''; 44 | height: 26px; 45 | width: 26px; 46 | left: 4px; 47 | bottom: 4px; 48 | background-color: white; 49 | -webkit-transition: 0.4s; 50 | transition: 0.4s; 51 | } 52 | 53 | input:checked + .slider { 54 | background-color: #31b975; 55 | } 56 | 57 | input:focus + .slider { 58 | box-shadow: 0 0 1px #31b975; 59 | } 60 | 61 | input:checked + .slider:before { 62 | -webkit-transform: translateX(26px); 63 | -ms-transform: translateX(26px); 64 | transform: translateX(26px); 65 | } 66 | 67 | .slider.round { 68 | border-radius: 34px; 69 | } 70 | 71 | .slider.round:before { 72 | border-radius: 50%; 73 | } 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🌈 Sorting Visualizer 2 | 3 | - This is a visualization tool for sorting algorithms made using React JS. 4 | - I build this project because I fascinated by the sorting algorithms and wanted to visualize them in action. 5 | - It also help others to comprehend the internal working of various sorting algorithms. 6 | 7 | ## Implemented Sorting Algorithms 8 | 9 | - Bubble Sort         O(n2) 10 | - Selection Sort     O(n2) 11 | - Insertion Sort      O(n2) 12 | - Merge Sort         O(n log n) 13 | - Quick Sort          O(n log n) 14 | - Heap Sort           O(n log n) 15 | 16 | ## Color Codes 17 | 18 | 🟧 `Randomized Array`

19 | 🟥 and 🟦 `Key comparisons`

20 | 🟩 `Sorted Array`

21 | 22 | ## Sorting Visualizer Interface 23 | > ## Landing Interface 24 | ![Default](https://user-images.githubusercontent.com/52111635/168355863-32b1f641-d6bd-479f-a929-79f05d648358.png) 25 | 26 |
27 | 28 | > ## Sorted Array 29 | ![Quick Sort](https://user-images.githubusercontent.com/52111635/168356389-5ee4da1e-f4c7-4f3d-bf57-e036f752efe3.png) 30 | 31 |
32 | 33 | 34 | ## To run this app locally 35 | - Download or clone this repo 36 | - In the project directory, run: 37 | #### `npm install` 38 | then 39 | #### `npm start` 40 | Runs the app in the development mode.\ 41 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 42 | 43 | The page will reload when you make changes.\ 44 | You may also see any lint errors in the console. 45 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/components/styles/slider.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | width: 30%; 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | } 7 | 8 | form { 9 | width: 90%; 10 | max-width: 500px; 11 | } 12 | 13 | .slider-title { 14 | font-size: 1.2rem; 15 | font-weight: 400; 16 | text-align: center; 17 | } 18 | 19 | form .speed-slider { 20 | display: flex; 21 | flex-direction: row; 22 | align-content: stretch; 23 | position: relative; 24 | width: 100%; 25 | height: 50px; 26 | user-select: none; 27 | } 28 | 29 | form .speed-slider::before { 30 | content: ' '; 31 | position: absolute; 32 | height: 2px; 33 | width: 100%; 34 | width: calc(100% * (2 / 3)); 35 | top: 50%; 36 | left: 50%; 37 | transform: translate(-50%, -50%); 38 | background: #000; 39 | } 40 | 41 | form .speed-slider input, 42 | form .speed-slider label { 43 | box-sizing: border-box; 44 | flex: 1; 45 | user-select: none; 46 | cursor: pointer; 47 | } 48 | 49 | form .speed-slider label { 50 | display: inline-block; 51 | position: relative; 52 | width: 20%; 53 | height: 100%; 54 | user-select: none; 55 | } 56 | 57 | form .speed-slider label::before { 58 | content: attr(current-speed); 59 | position: absolute; 60 | left: 50%; 61 | padding-top: 10px; 62 | transform: translate(-50%, 45px); 63 | font-size: 14px; 64 | letter-spacing: 0.4px; 65 | font-weight: 400; 66 | white-space: nowrap; 67 | opacity: 0.85; 68 | transition: all 0.15s ease-in-out; 69 | } 70 | 71 | form .speed-slider label::after { 72 | content: ' '; 73 | position: absolute; 74 | left: 50%; 75 | top: 50%; 76 | transform: translate(-50%, -50%); 77 | width: 30px; 78 | height: 30px; 79 | border: 2px solid #000; 80 | background: #fff; 81 | border-radius: 50%; 82 | pointer-events: none; 83 | user-select: none; 84 | z-index: 1; 85 | cursor: pointer; 86 | transition: all 0.15s ease-in-out; 87 | } 88 | 89 | form .speed-slider label:hover::after { 90 | transform: translate(-50%, -50%) scale(1.25); 91 | } 92 | 93 | form .speed-slider input { 94 | display: none; 95 | } 96 | 97 | form .speed-slider input:checked + label::before { 98 | font-weight: 800; 99 | opacity: 1; 100 | } 101 | 102 | form .speed-slider input:checked + label::after { 103 | border-width: 4px; 104 | transform: translate(-50%, -50%) scale(0.75); 105 | } 106 | 107 | form .speed-slider input:checked ~ .slider-position { 108 | opacity: 1; 109 | } 110 | 111 | form .speed-slider input:checked:nth-child(1) ~ .slider-position { 112 | left: 16.7%; 113 | } 114 | 115 | form .speed-slider input:checked:nth-child(3) ~ .slider-position { 116 | left: 50%; 117 | } 118 | 119 | form .speed-slider input:checked:nth-child(5) ~ .slider-position { 120 | left: 83.3%; 121 | } 122 | 123 | form .speed-slider .slider-position { 124 | display: block; 125 | position: absolute; 126 | top: 50%; 127 | width: 12px; 128 | height: 12px; 129 | background: #000; 130 | border-radius: 50%; 131 | transition: all 0.15s ease-in-out; 132 | transform: translate(-50%, -50%); 133 | border: 2px solid #fff; 134 | opacity: 0; 135 | z-index: 2; 136 | } 137 | 138 | form:valid .speed-slider input + label::before { 139 | transform: translate(-50%, 45px) scale(0.9); 140 | transition: all 0.15s linear; 141 | } 142 | 143 | form:valid .speed-slider input:checked + label::before { 144 | transform: translate(-50%, 45px) scale(1.1); 145 | transition: all 0.15s linear; 146 | } 147 | 148 | form + button { 149 | display: block; 150 | position: relative; 151 | margin: 56px auto 0; 152 | padding: 10px 20px; 153 | appearance: none; 154 | transition: all 0.15s ease-in-out; 155 | font-family: inherit; 156 | font-size: 24px; 157 | font-weight: 600; 158 | background: #fff; 159 | border: 2px solid #000; 160 | border-radius: 8px; 161 | outline: 0; 162 | user-select: none; 163 | cursor: pointer; 164 | } 165 | 166 | form + button:hover { 167 | background: #000; 168 | color: #fff; 169 | } 170 | 171 | form + button:hover:active { 172 | transform: scale(0.9); 173 | } 174 | 175 | form + button:focus { 176 | background: #4caf50; 177 | border-color: #4caf50; 178 | color: #fff; 179 | pointer-events: none; 180 | } 181 | 182 | form + button:focus::before { 183 | animation: spin 1s linear infinite; 184 | } 185 | 186 | form + button::before { 187 | display: inline-block; 188 | width: 0; 189 | opacity: 0; 190 | content: '\f3f4'; 191 | font-family: 'Font Awesome 5 Pro'; 192 | font-weight: 900; 193 | margin-right: 0; 194 | transform: rotate(0deg); 195 | } 196 | 197 | form:invalid + button { 198 | pointer-events: none; 199 | opacity: 0.25; 200 | } 201 | 202 | @keyframes spin { 203 | from { 204 | transform: rotate(0deg); 205 | width: 24px; 206 | opacity: 1; 207 | margin-right: 12px; 208 | } 209 | to { 210 | transform: rotate(360deg); 211 | width: 24px; 212 | opacity: 1; 213 | margin-right: 12px; 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/components/Visualizer.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react' 2 | import useSound from 'use-sound' 3 | import sound1 from './sounds/sound1.wav' 4 | import sound2 from './sounds/sound2.wav' 5 | import Button from './assets/Button' 6 | import Dropdown from './assets/Dropdown' 7 | import Slider from './assets/Slider' 8 | import Toggle from './assets/Toggle' 9 | 10 | const ARRAYSIZE = 100 11 | 12 | const Visualizer = () => { 13 | const [primaryArray, setPrimaryArray] = useState([]) 14 | const [algorithm, setAlgorithm] = useState('bubbleSort') 15 | const [animationSpeed, setAnimationSpeed] = useState(50) 16 | const [soundOn, setSoundOn] = useState(true) 17 | const [disableOptions, setDisableOptions] = useState(false) 18 | const [playBeep1] = useSound(sound1, { volume: soundOn ? 0.15 : 0 }) 19 | const [playBeep2] = useSound(sound2, { volume: soundOn ? 0.05 : 0 }) 20 | 21 | const randomizeArray = () => { 22 | for (let i = 0; i < primaryArray.length; i++) { 23 | let bar = document.getElementById(i).style 24 | bar.backgroundColor = '#ff7f50' 25 | } 26 | let array = [] 27 | for (let i = 0; i < ARRAYSIZE; i++) { 28 | array.push(randomVals(20, 400)) 29 | } 30 | 31 | setPrimaryArray(array) 32 | } 33 | 34 | const randomVals = (min, max) => { 35 | let randomVal = Math.floor(Math.random() * (max - min + 1) + min) 36 | return randomVal 37 | } 38 | 39 | useEffect(() => { 40 | randomizeArray() 41 | }, []) 42 | 43 | const sleep = (milliSeconds) => { 44 | return new Promise((resolve) => setTimeout(resolve, milliSeconds)) 45 | } 46 | 47 | const finishedAnimation = async () => { 48 | for (let i = 0; i < primaryArray.length; i++) { 49 | let bar = document.getElementById(i).style 50 | bar.backgroundColor = 'green' 51 | playBeep1() 52 | await sleep(animationSpeed) 53 | } 54 | setDisableOptions(false) 55 | } 56 | 57 | const handleSorting = () => { 58 | setDisableOptions(true) 59 | switch (algorithm) { 60 | case 'bubbleSort': 61 | bubbleSort() 62 | break 63 | case 'selectionSort': 64 | selectionSort() 65 | break 66 | case 'insertionSort': 67 | insertionSort() 68 | break 69 | case 'mergeSort': 70 | mergeSort() 71 | break 72 | case 'quickSort': 73 | quickSort() 74 | break 75 | case 'heapSort': 76 | heapSort() 77 | break 78 | default: 79 | break 80 | } 81 | } 82 | 83 | // ------------ ALGORITHMS ------------ // 84 | 85 | // Bubble Sort 86 | const bubbleSort = async () => { 87 | let currentArr = primaryArray 88 | let sorted = false 89 | setAlgorithm({ name: 'Bubble Sort', timeComplexity: 'O(n^2)' }) 90 | 91 | while (!sorted) { 92 | sorted = true 93 | 94 | for (let i = 0; i < currentArr.length - 1; i++) { 95 | for (let j = 0; j < currentArr.length - i - 1; j++) { 96 | if (currentArr[j] > currentArr[j + 1]) { 97 | let temp = currentArr[j] 98 | currentArr[j] = currentArr[j + 1] 99 | currentArr[j + 1] = temp 100 | setPrimaryArray([...primaryArray, currentArr]) 101 | 102 | let bar1 = document.getElementById(j).style 103 | let bar2 = document.getElementById(j + 1).style 104 | bar1.backgroundColor = '#DC143C' 105 | bar2.backgroundColor = '#6A5ACD' 106 | 107 | await sleep(animationSpeed) 108 | 109 | bar1.backgroundColor = '#FF7F50' 110 | bar2.backgroundColor = '#FF7F50' 111 | 112 | sorted = false 113 | playBeep1() 114 | } 115 | } 116 | playBeep2() 117 | } 118 | if (sorted) finishedAnimation() 119 | } 120 | } 121 | 122 | // Selection Sort 123 | const selectionSort = async () => { 124 | let currentArr = primaryArray 125 | let sorted = false 126 | setAlgorithm({ name: 'Selection Sort', timeComplexity: 'O(n^2)' }) 127 | 128 | while (!sorted) { 129 | sorted = true 130 | 131 | for (let i = 0; i < currentArr.length - 1; i++) { 132 | for (let j = i + 1; j < currentArr.length; j++) { 133 | if (currentArr[i] > currentArr[j]) { 134 | let swap1 = currentArr[i] 135 | let swap2 = currentArr[j] 136 | currentArr[i] = swap2 137 | currentArr[j] = swap1 138 | setPrimaryArray([...primaryArray, currentArr]) 139 | 140 | let bar1 = document.getElementById(i).style 141 | let bar2 = document.getElementById(j).style 142 | bar1.backgroundColor = '#DC143C' 143 | bar2.backgroundColor = '#6A5ACD' 144 | 145 | await sleep(animationSpeed) 146 | 147 | bar1.backgroundColor = '#FF7F50' 148 | bar2.backgroundColor = '#FF7F50' 149 | 150 | sorted = false 151 | playBeep1() 152 | } 153 | } 154 | playBeep2() 155 | } 156 | if (sorted) finishedAnimation() 157 | } 158 | } 159 | 160 | // Insertion Sort 161 | const insertionSort = async () => { 162 | let currentArr = primaryArray 163 | let sorted = false 164 | setAlgorithm({ name: 'Insertion Sort', timeComplexity: 'O(n^2)' }) 165 | 166 | while (!sorted) { 167 | sorted = true 168 | 169 | for (let i = 1; i < currentArr.length; i++) { 170 | let current = currentArr[i] 171 | let j = i - 1 172 | while (j >= 0 && currentArr[j] > current) { 173 | currentArr[j + 1] = currentArr[j] 174 | setPrimaryArray([...primaryArray, currentArr]) 175 | 176 | let bar1 = document.getElementById(j + 1).style 177 | let bar2 = document.getElementById(j).style 178 | bar1.backgroundColor = '#DC143C' 179 | bar2.backgroundColor = '#6A5ACD' 180 | 181 | await sleep(animationSpeed) 182 | 183 | bar1.backgroundColor = '#FF7F50' 184 | bar2.backgroundColor = '#FF7F50' 185 | 186 | j-- 187 | sorted = false 188 | playBeep1() 189 | } 190 | currentArr[j + 1] = current 191 | setPrimaryArray([...primaryArray, currentArr]) 192 | playBeep2() 193 | } 194 | if (sorted) finishedAnimation() 195 | } 196 | } 197 | 198 | // Merge Sort 199 | const mergeSort = async () => { 200 | let currentArr = primaryArray 201 | setAlgorithm({ name: 'Merge Sort', timeComplexity: 'O(n log(n))' }) 202 | 203 | await sort(currentArr, 0, currentArr.length - 1) 204 | finishedAnimation() 205 | } 206 | 207 | const sort = async (arr, low, high) => { 208 | if (low < high) { 209 | let mid = Math.floor((low + high) / 2) 210 | await sort(arr, low, mid) 211 | await sort(arr, mid + 1, high) 212 | await merge(arr, low, mid, high) 213 | } 214 | } 215 | 216 | const merge = async (arr, low, mid, high) => { 217 | let i = low 218 | let j = mid + 1 219 | let k = 0 220 | let tempArr = [] 221 | 222 | while (i <= mid && j <= high) { 223 | if (arr[i] < arr[j]) { 224 | tempArr[k] = arr[i] 225 | i++ 226 | k++ 227 | } else { 228 | tempArr[k] = arr[j] 229 | j++ 230 | k++ 231 | } 232 | setPrimaryArray([...primaryArray, tempArr]) 233 | 234 | let bar1 = document.getElementById(i).style 235 | let bar2 = document.getElementById(j).style 236 | bar1.backgroundColor = '#DC143C' 237 | bar2.backgroundColor = '#6A5ACD' 238 | 239 | await sleep(animationSpeed) 240 | 241 | bar1.backgroundColor = '#FF7F50' 242 | bar2.backgroundColor = '#FF7F50' 243 | 244 | playBeep1() 245 | } 246 | 247 | while (i <= mid) { 248 | tempArr[k] = arr[i] 249 | 250 | setPrimaryArray([...primaryArray, tempArr]) 251 | 252 | let bar1 = document.getElementById(i).style 253 | let bar2 = document.getElementById(j).style 254 | bar1.backgroundColor = '#DC143C' 255 | bar2.backgroundColor = '#6A5ACD' 256 | 257 | await sleep(animationSpeed) 258 | 259 | bar1.backgroundColor = '#FF7F50' 260 | bar2.backgroundColor = '#FF7F50' 261 | 262 | playBeep1() 263 | 264 | i++ 265 | k++ 266 | } 267 | 268 | while (j <= high) { 269 | tempArr[k] = arr[j] 270 | 271 | setPrimaryArray([...primaryArray, tempArr]) 272 | 273 | let bar1 = document.getElementById(i).style 274 | let bar2 = document.getElementById(j).style 275 | bar1.backgroundColor = '#DC143C' 276 | bar2.backgroundColor = '#6A5ACD' 277 | 278 | await sleep(animationSpeed) 279 | 280 | bar1.backgroundColor = '#FF7F50' 281 | bar2.backgroundColor = '#FF7F50' 282 | 283 | playBeep1() 284 | 285 | j++ 286 | k++ 287 | } 288 | 289 | for (let i = low; i <= high; i++) { 290 | arr[i] = tempArr[i - low] 291 | setPrimaryArray([...primaryArray, arr]) 292 | playBeep2() 293 | } 294 | } 295 | 296 | // Quick Sort 297 | const quickSort = async () => { 298 | setAlgorithm({ name: 'Quick Sort', timeComplexity: 'O(n log(n))' }) 299 | let currentArr = primaryArray 300 | 301 | await sorts(currentArr, 0, currentArr.length - 1) 302 | finishedAnimation() 303 | } 304 | 305 | const sorts = async (arr, left, right) => { 306 | if (left < right) { 307 | let partitionIndex = partition(arr, left, right) 308 | 309 | setPrimaryArray([...primaryArray, arr]) 310 | await sleep(animationSpeed) 311 | playBeep2() 312 | await sorts(arr, left, partitionIndex - 1) 313 | await sorts(arr, partitionIndex + 1, right) 314 | } 315 | } 316 | 317 | const partition = (arr, left, right) => { 318 | let pivot = arr[right] 319 | let i = left - 1 320 | playBeep1() 321 | for (let j = left; j < right; j++) { 322 | if (arr[j] < pivot) { 323 | i++ 324 | let temp = arr[i] 325 | arr[i] = arr[j] 326 | arr[j] = temp 327 | 328 | let bar1 = document.getElementById(i).style 329 | let bar2 = document.getElementById(j).style 330 | bar1.backgroundColor = '#DC143C' 331 | bar2.backgroundColor = '#6A5ACD' 332 | 333 | setTimeout(() => { 334 | bar1.backgroundColor = '#ff7f50' 335 | bar2.backgroundColor = '#ff7f50' 336 | }, 200) 337 | 338 | setPrimaryArray([...primaryArray, arr]) 339 | } 340 | } 341 | 342 | let temp = arr[i + 1] 343 | arr[i + 1] = arr[right] 344 | arr[right] = temp 345 | 346 | return i + 1 347 | } 348 | 349 | // Heap Sort 350 | const heapSort = async () => { 351 | let arr = primaryArray 352 | let length = arr.length 353 | let index = Math.floor(length / 2 - 1) 354 | let lastChild = length - 1 355 | 356 | setAlgorithm({ name: 'Heap Sort', timeComplexity: 'O(n log(n))' }) 357 | 358 | while (index >= 0) { 359 | await heapify(arr, length, index) 360 | index-- 361 | 362 | setPrimaryArray([...primaryArray, arr]) 363 | 364 | if (index >= 0) { 365 | let bar1 = document.getElementById(index).style 366 | let bar2 = document.getElementById(index + 1).style 367 | bar1.backgroundColor = '#DC143C' 368 | bar2.backgroundColor = '#6A5ACD' 369 | 370 | await sleep(animationSpeed) 371 | 372 | playBeep1() 373 | 374 | bar1.backgroundColor = '#FF7F50' 375 | bar2.backgroundColor = '#FF7F50' 376 | } else { 377 | await sleep(animationSpeed) 378 | } 379 | } 380 | 381 | while (lastChild >= 0) { 382 | let swap1 = arr[0] 383 | let swap2 = arr[lastChild] 384 | 385 | arr[0] = swap2 386 | arr[lastChild] = swap1 387 | await heapify(arr, lastChild, 0) 388 | lastChild-- 389 | playBeep2() 390 | 391 | setPrimaryArray([...primaryArray, arr]) 392 | 393 | if (index >= 0) { 394 | let bar1 = document.getElementById(lastChild).style 395 | let bar2 = document.getElementById(0).style 396 | bar1.backgroundColor = '#DC143C' 397 | bar2.backgroundColor = '#6A5ACD' 398 | 399 | bar1.backgroundColor = '#FF7F50' 400 | bar2.backgroundColor = '#FF7F50' 401 | } else { 402 | await sleep(animationSpeed) 403 | } 404 | } 405 | 406 | finishedAnimation() 407 | } 408 | 409 | const heapify = async (arr, length, index) => { 410 | let largest = index 411 | let leftNode = index * 2 + 1 412 | let rightNode = leftNode + 1 413 | 414 | if (arr[leftNode] > arr[largest] && leftNode < length) { 415 | largest = leftNode 416 | } 417 | 418 | if (arr[rightNode] > arr[largest] && rightNode < length) { 419 | largest = rightNode 420 | } 421 | 422 | if (largest !== index) { 423 | let swap1 = arr[index] 424 | let swap2 = arr[largest] 425 | arr[index] = swap2 426 | arr[largest] = swap1 427 | 428 | let bar1 = document.getElementById(index).style 429 | let bar2 = document.getElementById(largest).style 430 | bar1.backgroundColor = '#DC143C' 431 | bar2.backgroundColor = '#6A5ACD' 432 | 433 | await sleep(animationSpeed) 434 | 435 | bar1.backgroundColor = '#FF7F50' 436 | bar2.backgroundColor = '#FF7F50' 437 | 438 | playBeep1() 439 | 440 | await heapify(arr, length, largest) 441 | } 442 | 443 | return arr 444 | } 445 | 446 | return ( 447 |
448 |
449 |
479 |
480 | {primaryArray && 481 | primaryArray.map((val, key) => { 482 | return ( 483 |
489 | ) 490 | })} 491 |
492 | {algorithm.name !== undefined && ( 493 |
494 |
Algorithm: {algorithm.name}
495 |
Time Complexity: {algorithm.timeComplexity}
496 |
497 | )} 498 |
499 | ) 500 | } 501 | 502 | export default Visualizer 503 | --------------------------------------------------------------------------------