├── .DS_Store ├── .gitignore ├── README.md ├── package-lock.json ├── package.json └── website ├── .DS_Store ├── app.css ├── imgs ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico └── site.webmanifest ├── index.html └── scripts ├── .DS_Store ├── bubble.js ├── helper_functions.js ├── insertionsort.js ├── main.js ├── mergesort.js ├── quicksort.js └── selectionsort.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakecondrey/sortingvisualizer/d7431aea208f8b69c8e1c2e29dfa80e2fb56dce8/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Sorting Visualization Tool



2 | 3 | live website: https://blakecondrey.github.io/sortingvisualizer/
4 | 5 | This website generates an array of random-heighted columns, and allows the user to visualize:
6 |
    7 |
  1. Bubble Sort Algorithm
  2. 8 |
  3. Insertion Sort Algorithm
  4. 9 |
  5. Selection Sort Algorithm
  6. 10 |
  7. Merge Sort Algorithm
  8. 11 |
  9. Quick Sort Algorithm
  10. 12 |


13 | The array size can be increased/decreased prior to sorting, and the sorting speed can be dynamically adjusted during the live sort.
14 | This project was a fantastic exercise to grasp the concepts of sorting algorithms, and gave me the chance to sharpen-up on JavaScript and Bootstrap. 15 |

16 | The source code may be forked or copy-pasted for your use.

17 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sortingvisualizer", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "array-union": { 8 | "version": "1.0.2", 9 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", 10 | "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", 11 | "requires": { 12 | "array-uniq": "^1.0.1" 13 | } 14 | }, 15 | "array-uniq": { 16 | "version": "1.0.3", 17 | "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", 18 | "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" 19 | }, 20 | "async": { 21 | "version": "2.6.3", 22 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", 23 | "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", 24 | "requires": { 25 | "lodash": "^4.17.14" 26 | } 27 | }, 28 | "balanced-match": { 29 | "version": "1.0.2", 30 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 31 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" 32 | }, 33 | "brace-expansion": { 34 | "version": "1.1.11", 35 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 36 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 37 | "requires": { 38 | "balanced-match": "^1.0.0", 39 | "concat-map": "0.0.1" 40 | } 41 | }, 42 | "commander": { 43 | "version": "2.20.3", 44 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 45 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" 46 | }, 47 | "commondir": { 48 | "version": "1.0.1", 49 | "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", 50 | "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" 51 | }, 52 | "concat-map": { 53 | "version": "0.0.1", 54 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 55 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 56 | }, 57 | "email-addresses": { 58 | "version": "3.1.0", 59 | "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz", 60 | "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==" 61 | }, 62 | "escape-string-regexp": { 63 | "version": "1.0.5", 64 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 65 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 66 | }, 67 | "filename-reserved-regex": { 68 | "version": "2.0.0", 69 | "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", 70 | "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=" 71 | }, 72 | "filenamify": { 73 | "version": "4.3.0", 74 | "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", 75 | "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", 76 | "requires": { 77 | "filename-reserved-regex": "^2.0.0", 78 | "strip-outer": "^1.0.1", 79 | "trim-repeated": "^1.0.0" 80 | } 81 | }, 82 | "find-cache-dir": { 83 | "version": "3.3.1", 84 | "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", 85 | "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", 86 | "requires": { 87 | "commondir": "^1.0.1", 88 | "make-dir": "^3.0.2", 89 | "pkg-dir": "^4.1.0" 90 | } 91 | }, 92 | "find-up": { 93 | "version": "4.1.0", 94 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", 95 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", 96 | "requires": { 97 | "locate-path": "^5.0.0", 98 | "path-exists": "^4.0.0" 99 | } 100 | }, 101 | "fs-extra": { 102 | "version": "8.1.0", 103 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", 104 | "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", 105 | "requires": { 106 | "graceful-fs": "^4.2.0", 107 | "jsonfile": "^4.0.0", 108 | "universalify": "^0.1.0" 109 | } 110 | }, 111 | "fs.realpath": { 112 | "version": "1.0.0", 113 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 114 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 115 | }, 116 | "gh-pages": { 117 | "version": "3.2.3", 118 | "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-3.2.3.tgz", 119 | "integrity": "sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg==", 120 | "requires": { 121 | "async": "^2.6.1", 122 | "commander": "^2.18.0", 123 | "email-addresses": "^3.0.1", 124 | "filenamify": "^4.3.0", 125 | "find-cache-dir": "^3.3.1", 126 | "fs-extra": "^8.1.0", 127 | "globby": "^6.1.0" 128 | } 129 | }, 130 | "glob": { 131 | "version": "7.1.7", 132 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", 133 | "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", 134 | "requires": { 135 | "fs.realpath": "^1.0.0", 136 | "inflight": "^1.0.4", 137 | "inherits": "2", 138 | "minimatch": "^3.0.4", 139 | "once": "^1.3.0", 140 | "path-is-absolute": "^1.0.0" 141 | } 142 | }, 143 | "globby": { 144 | "version": "6.1.0", 145 | "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", 146 | "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", 147 | "requires": { 148 | "array-union": "^1.0.1", 149 | "glob": "^7.0.3", 150 | "object-assign": "^4.0.1", 151 | "pify": "^2.0.0", 152 | "pinkie-promise": "^2.0.0" 153 | } 154 | }, 155 | "graceful-fs": { 156 | "version": "4.2.8", 157 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", 158 | "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" 159 | }, 160 | "inflight": { 161 | "version": "1.0.6", 162 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 163 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 164 | "requires": { 165 | "once": "^1.3.0", 166 | "wrappy": "1" 167 | } 168 | }, 169 | "inherits": { 170 | "version": "2.0.4", 171 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 172 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 173 | }, 174 | "jsonfile": { 175 | "version": "4.0.0", 176 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", 177 | "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", 178 | "requires": { 179 | "graceful-fs": "^4.1.6" 180 | } 181 | }, 182 | "locate-path": { 183 | "version": "5.0.0", 184 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", 185 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", 186 | "requires": { 187 | "p-locate": "^4.1.0" 188 | } 189 | }, 190 | "lodash": { 191 | "version": "4.17.21", 192 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 193 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" 194 | }, 195 | "make-dir": { 196 | "version": "3.1.0", 197 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", 198 | "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", 199 | "requires": { 200 | "semver": "^6.0.0" 201 | } 202 | }, 203 | "minimatch": { 204 | "version": "3.0.4", 205 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 206 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 207 | "requires": { 208 | "brace-expansion": "^1.1.7" 209 | } 210 | }, 211 | "object-assign": { 212 | "version": "4.1.1", 213 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 214 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 215 | }, 216 | "once": { 217 | "version": "1.4.0", 218 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 219 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 220 | "requires": { 221 | "wrappy": "1" 222 | } 223 | }, 224 | "p-limit": { 225 | "version": "2.3.0", 226 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 227 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 228 | "requires": { 229 | "p-try": "^2.0.0" 230 | } 231 | }, 232 | "p-locate": { 233 | "version": "4.1.0", 234 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", 235 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", 236 | "requires": { 237 | "p-limit": "^2.2.0" 238 | } 239 | }, 240 | "p-try": { 241 | "version": "2.2.0", 242 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 243 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" 244 | }, 245 | "path-exists": { 246 | "version": "4.0.0", 247 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 248 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" 249 | }, 250 | "path-is-absolute": { 251 | "version": "1.0.1", 252 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 253 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 254 | }, 255 | "pify": { 256 | "version": "2.3.0", 257 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 258 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" 259 | }, 260 | "pinkie": { 261 | "version": "2.0.4", 262 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 263 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" 264 | }, 265 | "pinkie-promise": { 266 | "version": "2.0.1", 267 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 268 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 269 | "requires": { 270 | "pinkie": "^2.0.0" 271 | } 272 | }, 273 | "pkg-dir": { 274 | "version": "4.2.0", 275 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", 276 | "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", 277 | "requires": { 278 | "find-up": "^4.0.0" 279 | } 280 | }, 281 | "semver": { 282 | "version": "6.3.0", 283 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 284 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" 285 | }, 286 | "strip-outer": { 287 | "version": "1.0.1", 288 | "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", 289 | "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", 290 | "requires": { 291 | "escape-string-regexp": "^1.0.2" 292 | } 293 | }, 294 | "trim-repeated": { 295 | "version": "1.0.0", 296 | "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", 297 | "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", 298 | "requires": { 299 | "escape-string-regexp": "^1.0.2" 300 | } 301 | }, 302 | "universalify": { 303 | "version": "0.1.2", 304 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 305 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" 306 | }, 307 | "wrappy": { 308 | "version": "1.0.2", 309 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 310 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 311 | } 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sortingvisualizer", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "deploy": "gh-pages -d website" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/blakecondrey/sortingvisualizer.git" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/blakecondrey/sortingvisualizer/issues" 18 | }, 19 | "homepage": "https://github.com/blakecondrey/sortingvisualizer", 20 | "dependencies": { 21 | "gh-pages": "^3.2.3" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /website/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakecondrey/sortingvisualizer/d7431aea208f8b69c8e1c2e29dfa80e2fb56dce8/website/.DS_Store -------------------------------------------------------------------------------- /website/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #0a192f; 3 | color: #e6f1ff 4 | } 5 | 6 | .array { 7 | background-color: #5d6f8c; 8 | } 9 | 10 | .speed { 11 | background-color: #5d6f8c; 12 | } 13 | 14 | .form-range { 15 | height: 40px; 16 | width: 190px; 17 | } 18 | 19 | .array-size-bar { 20 | background-color: #28559e; 21 | } 22 | 23 | .sort-speed { 24 | background-color: #28559e; 25 | } 26 | 27 | .button-hover:hover { 28 | transform: scale(1.15); 29 | background-color: #64ffda; 30 | color:#0a192f; 31 | } 32 | 33 | .generated-column { 34 | background: #64ffda; 35 | border: 1pt solid black; 36 | width: 15px; 37 | transition: 0.1s all ease; 38 | } 39 | 40 | .sort-column { 41 | height: 550px; 42 | transition: 2s all ease; 43 | } 44 | 45 | .column-finished { 46 | background: #64ffda; 47 | border: 1pt solid black; 48 | width: 15px; 49 | transition: 0.1s all ease; 50 | } 51 | 52 | .page-footer { 53 | background: #e6f1ff; 54 | height: 1em; 55 | padding: 50px; 56 | position: relative; 57 | color: #0a192f; 58 | } 59 | -------------------------------------------------------------------------------- /website/imgs/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakecondrey/sortingvisualizer/d7431aea208f8b69c8e1c2e29dfa80e2fb56dce8/website/imgs/android-chrome-192x192.png -------------------------------------------------------------------------------- /website/imgs/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakecondrey/sortingvisualizer/d7431aea208f8b69c8e1c2e29dfa80e2fb56dce8/website/imgs/android-chrome-512x512.png -------------------------------------------------------------------------------- /website/imgs/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakecondrey/sortingvisualizer/d7431aea208f8b69c8e1c2e29dfa80e2fb56dce8/website/imgs/apple-touch-icon.png -------------------------------------------------------------------------------- /website/imgs/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakecondrey/sortingvisualizer/d7431aea208f8b69c8e1c2e29dfa80e2fb56dce8/website/imgs/favicon-16x16.png -------------------------------------------------------------------------------- /website/imgs/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakecondrey/sortingvisualizer/d7431aea208f8b69c8e1c2e29dfa80e2fb56dce8/website/imgs/favicon-32x32.png -------------------------------------------------------------------------------- /website/imgs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakecondrey/sortingvisualizer/d7431aea208f8b69c8e1c2e29dfa80e2fb56dce8/website/imgs/favicon.ico -------------------------------------------------------------------------------- /website/imgs/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Sorting Visualizer 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 | 26 | 33 |
34 |
Sorting Visualization Tool
35 |
36 |
37 |
38 |
39 |
Array Size
40 |
8
41 | 42 |
150
43 |
44 |
45 |
46 |
47 | 48 | 49 | 50 | 51 | 52 |
53 |
54 |
55 |
56 |
Sort Speed
57 |
-
58 | 59 |
+
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | 75 |
76 |
77 |
78 |
79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /website/scripts/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blakecondrey/sortingvisualizer/d7431aea208f8b69c8e1c2e29dfa80e2fb56dce8/website/scripts/.DS_Store -------------------------------------------------------------------------------- /website/scripts/bubble.js: -------------------------------------------------------------------------------- 1 | /* Bubble Sort arranges 'N' elements of an array/list in ascending order 2 | * by commencing at 0th index and comparing it's value to the 1st index. 3 | * If 0th > 1st, the elements will swap values. The algorithm then proceeds 4 | * to the next indexed elements and performs the comparing function and 5 | * and repeats until array is sorted. 6 | * Bubble Sort is the simplest sorting method. 7 | * Space-time complexity of O(n^2) 8 | */ 9 | async function bubbleSort() { 10 | disableUserInput(); 11 | // Select columns in the array for manipulation in algorithm 12 | const column = document.querySelectorAll(".column"); 13 | // flag for while loop 14 | let isSorted = false; 15 | // counter for round comparison | incremented after for-loop escape 16 | let counter = 0; 17 | // outer loop to traverse length of array 18 | while(!isSorted) { 19 | isSorted = true; 20 | // inner loop to traverse and compare column values 21 | for (let i = 0; i < column.length - 1 - counter; i++) { 22 | if (compareColumns(column[i], column[i + 1])) { 23 | markColumn(column[i], COLORS.selector); 24 | markColumn(column[i + 1], COLORS.selector); 25 | // swapColumns(column[i], column[i + 1]); 26 | await pauseSorter(pauseTime / 25); 27 | swapColumns(column[i], column[i + 1]); 28 | markColumn(column[i], COLORS.deselector); 29 | markColumn(column[i + 1], COLORS.deselector); 30 | await pauseSorter(pauseTime / 25); 31 | // reenter while loop 32 | isSorted = false; 33 | } 34 | // breaks loop condition to mark columns as sorted 35 | // prior to compare function 36 | else { 37 | markColumn(column[i], COLORS.deselector); 38 | markColumn(column[i + 1], COLORS.deselector); 39 | await pauseSorter(pauseTime / 25); 40 | // reenter while loop 41 | isSorted = false; 42 | } 43 | // once columns are sorted, loop traverses array 44 | // of columns to return to original color 45 | for (let j = i; j >= 0; j--) { 46 | markColumn(column[j], COLORS.complete); 47 | } 48 | } 49 | // increase counter for inner loop comparison 50 | counter++; 51 | } 52 | // return to completed color 53 | for (let k = column.length - 1; k >= 0; k--) { 54 | markColumn(column[k], COLORS.complete) 55 | await pauseSorter(100 / newArray.length); 56 | } 57 | 58 | enableUserInput(); 59 | } -------------------------------------------------------------------------------- /website/scripts/helper_functions.js: -------------------------------------------------------------------------------- 1 | // Helper functions 2 | 3 | // visually selects column in array 4 | function markColumn(column, color) { 5 | column.style.background = color; 6 | } 7 | 8 | // compares two columns using greater-than to prepare for swap 9 | function compareColumns(colOne, colTwo) { 10 | if (parseInt(colOne.style.height) > parseInt(colTwo.style.height)) { 11 | return true; 12 | } 13 | return false; 14 | } 15 | 16 | // column values swapped 17 | function swapColumns (colOne, colTwo) { 18 | let tempCol = colOne.style.height; 19 | colOne.style.height = colTwo.style.height; 20 | colTwo.style.height = tempCol; 21 | } 22 | 23 | // HTML id's for disable/enable functions 24 | const ALGORITHMS = [ 25 | "#bubble-sort", 26 | "#insertion-sort", 27 | "#selection-sort", 28 | "#merge-sort", 29 | "#quick-sort" 30 | ] 31 | 32 | // function to disable buttons and inputs during sort 33 | function disableUserInput() { 34 | for (i in ALGORITHMS) { 35 | document.querySelector(ALGORITHMS[i]).disabled = true; 36 | } 37 | document.querySelector("#generate-array").disabled = true; 38 | document.querySelector("#array-size").disabled = true; 39 | document.querySelector("#sort-speed").disabled = false; 40 | } 41 | 42 | // after sort, function enables buttons for new arrays/sorts 43 | function enableUserInput() { 44 | for (i in ALGORITHMS) { 45 | document.querySelector(ALGORITHMS[i]).disabled = false; 46 | } 47 | document.querySelector("#generate-array").disabled = false; 48 | document.querySelector("#array-size").disabled = false; 49 | document.querySelector("#sort-speed").disabled = true; 50 | } 51 | 52 | // colors for marking function 53 | const COLORS = { 54 | selector: '#ff0000', 55 | deselector: '#28559e', 56 | complete: '#64ffda', 57 | pivot: '#BF40BF', 58 | }; 59 | 60 | // animation function that pauses sorter for visual effect 61 | let pauseTime = 250; 62 | function pauseSorter(ms) { 63 | return new Promise(resolve => { 64 | setTimeout(() => { resolve('') }, ms); 65 | }) 66 | } 67 | 68 | // speed toggler calls animation (pause) function to 69 | // determine speed of algorithm 70 | let sortSpeed = document.getElementById("sort-speed"); 71 | sortSpeed.addEventListener("input", () => { 72 | pauseTime = 250 / (parseInt(sortSpeed.value)); 73 | }) -------------------------------------------------------------------------------- /website/scripts/insertionsort.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Insertion Sort algorithm virtually splits array of N elements into 3 | * sorted and unsorted parts. Elements in the unsorted part of the array 4 | * are selected and inserted into correct position into the sorted 5 | * of the array, similar to the way humans sort and organize a hand 6 | * of cards dealt in nearly every card-playing game. 7 | */ 8 | 9 | async function insertionSort() { 10 | disableUserInput(); 11 | // Select columns in the array for manipulation in algorithm 12 | const column = document.querySelectorAll(".column"); 13 | // Iterate from column[1] to column[n] (n = length = last element) 14 | for (let i = 1; i < column.length; i++) { 15 | // set key for comparison to predecessor 16 | let key = column[i].style.height; 17 | // set column for comparison to key 18 | let j = i - 1; 19 | markColumn(column[i], COLORS.selector); 20 | await pauseSorter(pauseTime / 25); 21 | markColumn(column[i], COLORS.deselector); 22 | // while-loop for comparison of col[j] to key moves elements of 23 | // col[0 -> i - 1] ahead of current position 24 | while (j >= 0 && (parseInt(column[j].style.height) > parseInt(key))) { 25 | swapColumns(column[j + 1], column[j]); 26 | markColumn(column[j], COLORS.selector); 27 | j--; 28 | await pauseSorter(pauseTime / 25); 29 | for (let k = i; k >=0; k--) { 30 | markColumn(column[k], COLORS.deselector); 31 | } 32 | } 33 | // values swap 34 | column[j + 1].style.height = key; 35 | } 36 | // columns are sorted and revert to original color 37 | for (let k = column.length - 1; k >= 0; k--) { 38 | markColumn(column[k], COLORS.complete); 39 | await pauseSorter(100 / newArray.length); 40 | } 41 | 42 | enableUserInput(); 43 | } -------------------------------------------------------------------------------- /website/scripts/main.js: -------------------------------------------------------------------------------- 1 | // create empty array to be implemented in startup 2 | let newArray = []; 3 | // sizing variable for user to choose size of array 4 | let arrayElement = document.getElementById("array-size"); 5 | document.querySelector("#sort-speed").disabled = true; 6 | 7 | // page generates random array of size of value 8 | // of input set in HTML for startup 9 | generateRandomArray(); 10 | 11 | arrayElement.addEventListener("input", generateRandomArray); 12 | 13 | function generateRandomArray() { 14 | newArray.length = 0; 15 | // HTML selects columns by ID 16 | const column = document.querySelector("#columns"); 17 | let arraySize = arrayElement.value; 18 | column.innerHTML = ''; 19 | for (let i = 0; i < arraySize; i++) { 20 | newArray.push(randomIntFromInterval(5, 700)); 21 | } 22 | const columns = document.querySelector("#columns"); 23 | // create columns to be generated 24 | for (let i = 0; i < arraySize; i++) { 25 | const column = document.createElement("div"); 26 | column.style.height = `${newArray[i] / 1.5}px`; 27 | column.classList.add('column'); 28 | column.classList.add('generated-column'); 29 | column.classList.add(`columnNo${i + 1}`); 30 | columns.appendChild(column); 31 | } 32 | } 33 | 34 | // https://stackoverflow.com/questions/4959975/generate-random-number-between-two-numbers-in-javascript 35 | function randomIntFromInterval(min, max) { 36 | return Math.floor(Math.random() * (max - min + 1)) + min; 37 | } 38 | 39 | 40 | -------------------------------------------------------------------------------- /website/scripts/mergesort.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Merge Sort is an algorithm that "divides and conquers", by splitting the 3 | * array into two halves, then calls itself for the two halves and 4 | * finshes by merging the two halves. 5 | * merge(column, start, middle, end) assumes that col[start...middle] 6 | * col[middle + 1, end] are sorted, completes merger of the sub-arrays 7 | * SEE https://en.wikipedia.org/wiki/File:Merge_sort_algorithm_diagram.svg for 8 | * a visual diagram. 9 | */ 10 | async function merge(column, start, middle, end) { 11 | const firstAuxillaryArrayValue = middle - start + 1; 12 | const secondAuxillaryArrayValue = end - middle; 13 | 14 | // temporary arrays 15 | let left = []; 16 | let right = []; 17 | 18 | // // copy data to temporary arrays of left and right (lines 17-27) 19 | 20 | for (let i = 0, j = i - 1; i < firstAuxillaryArrayValue, j < secondAuxillaryArrayValue; i++, j++) { 21 | markColumn(column[start + i], COLORS.selector); 22 | markColumn(column[middle + 1 + j], COLORS.selector); 23 | await pauseSorter(pauseTime / 10); 24 | left[i] = column[start + i].style.height; 25 | right[j] = column[middle + 1 + j].style.height; 26 | } 27 | 28 | //------------PREVIOUS IMPLEMENTATION BELOW-----------------| 29 | // for (let i = 0; i < firstAuxillaryArrayValue; i++) { | 30 | // markColumn(column[start + i], COLORS.selector); | 31 | // left[i] = column[start + i].style.height; | 32 | // await pauseSorter(pauseTime); | 33 | // } | 34 | // | 35 | // for (let i = 0; i < secondAuxillaryArrayValue; i++) { | 36 | // markColumn(column[middle + 1 + i], COLORS.selector); | 37 | // right[i] = column[middle + 1 + i].style.height; | 38 | // await pauseSorter(pauseTime); | 39 | // } | 40 | //----------------------------------------------------------| 41 | 42 | // i = 0 is init index of first subarray 43 | // j = 0 is init index of second subarray 44 | // k = start is init index of merged subarray 45 | let i = 0, j = 0, k = start; 46 | 47 | while( i < firstAuxillaryArrayValue && j < secondAuxillaryArrayValue) { 48 | //compareColumns() obsolete for merge() 49 | // must be <= 50 | if (parseInt(left[i]) <= parseInt(right[j])) { 51 | markColumn(column[k], COLORS.deselector); 52 | // virtual swap 53 | column[k].style.height = left[i]; 54 | i++; 55 | //k++; 56 | } 57 | else { 58 | markColumn(column[k], COLORS.deselector); 59 | column[k].style.height = right[j]; 60 | j++; 61 | // k++; 62 | } 63 | k++; 64 | await pauseSorter(pauseTime / 10); 65 | } 66 | 67 | // copy remaining elements of left[], if any 68 | while (i < firstAuxillaryArrayValue) { 69 | markColumn(column[k], COLORS.deselector); 70 | column[k].style.height = left[i]; 71 | i++; 72 | k++; 73 | await pauseSorter(pauseTime); 74 | } 75 | // copy remaining elents of right[], if any 76 | while (j < secondAuxillaryArrayValue) { 77 | markColumn(column[k], COLORS.deselector); 78 | column[k].style.height = right[j]; 79 | j++; 80 | k++; 81 | await pauseSorter(pauseTime / 10); 82 | } 83 | } 84 | 85 | // left is left index, right is right index of sub-array of array to sort 86 | async function mergeHelper(column, left, right) { 87 | if (left >= right) { 88 | // recursive return 89 | return; 90 | } 91 | const mid = left + Math.floor((right - left) / 2); 92 | await mergeHelper(column, left, mid); 93 | await mergeHelper(column, mid + 1, right); 94 | await merge(column, left, mid, right); 95 | } 96 | 97 | // inside mergeSort() driver function 98 | async function mergeSort() { 99 | disableUserInput(); 100 | let column = document.querySelectorAll(".column"); 101 | await mergeHelper(column, 0, parseInt(column.length) - 1); 102 | for (let k = column.length - 1; k >= 0; k--) { 103 | markColumn(column[k], COLORS.complete); 104 | await pauseSorter(100 / newArray.length); 105 | } 106 | 107 | enableUserInput(); 108 | } -------------------------------------------------------------------------------- /website/scripts/quicksort.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Quick Sort algorithm "divides and conquers", similar to the Merge Sort. 3 | * An element is selected as the pivot and partitions a given array 4 | * around the pivot. In the implementation below, the pivot is selected 5 | * as the furthermost (or last) element and orders the pivot element 6 | * of the array in the correct position of sorted array while 7 | * selecting elements smaller than pivot's element to the left of pivot 8 | * and elements greater than pivot to the right. 9 | */ 10 | async function partition(column, left, right) { 11 | // places pivot equal to last element 12 | let pivot = right; 13 | // index smaller element = right position of pivot 14 | let i = left - 1; 15 | markColumn(column[pivot], COLORS.pivot); 16 | 17 | for (let j = left; j <= right - 1; j++) { 18 | markColumn(column[j], COLORS.selector); 19 | await pauseSorter(pauseTime / 10); 20 | // if pivot is greater than current element 21 | if (compareColumns(column[pivot], column[j])) { 22 | // increment index of smaller element 23 | i++; 24 | markColumn(column[i], COLORS.selector); 25 | markColumn(column[j], COLORS.selector); 26 | await pauseSorter(pauseTime / 10); 27 | swapColumns(column[i], column[j]); 28 | markColumn(column[i], COLORS.deselector); 29 | markColumn(column[j], COLORS.deselector); 30 | await pauseSorter(pauseTime / 10); 31 | } 32 | } 33 | // swap columns in array 34 | swapColumns(column[i + 1], column[right]); 35 | 36 | await pauseSorter(pauseTime / 10); 37 | // 38 - 44 are for visual purpose 38 | for(let k = 0; k <= pivot; k++) { 39 | // markColumn(column[k], COLORS.deselector); 40 | markColumn(column[k], COLORS.deselector); 41 | 42 | } 43 | 44 | for (let k = pivot + 1; k < column.length; k++) { 45 | markColumn(column[k], COLORS.deselector); 46 | } 47 | 48 | return i + 1; 49 | } 50 | 51 | /* 52 | * recursive function implemented in main quickSort() 53 | * column param is array to be sorted, 54 | * left param is the starting index, 55 | * right param is the end index. 56 | */ 57 | async function quickSortHelper(column, left, right) { 58 | if (left < right) { 59 | // set index of partitioner. 60 | let partitionIndex = await partition(column, left, right); 61 | // recursive function to sort elements before and after partition 62 | await quickSortHelper(column, left, partitionIndex - 1); 63 | await quickSortHelper(column, partitionIndex + 1, right); 64 | } 65 | } 66 | 67 | // driver quickSort() function 68 | async function quickSort() { 69 | disableUserInput(); 70 | let column = document.querySelectorAll(".column"); 71 | for (let k = column.length - 1; k >= 0; k--) { 72 | markColumn(column[k], COLORS.complete); 73 | await pauseSorter(100 / newArray.length); 74 | } 75 | await quickSortHelper(column, 0, parseInt(column.length) - 1); 76 | for (let k = column.length - 1; k >= 0; k--) { 77 | markColumn(column[k], COLORS.complete); 78 | await pauseSorter(100 / newArray.length); 79 | } 80 | enableUserInput(); 81 | } -------------------------------------------------------------------------------- /website/scripts/selectionsort.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Selection Sort sort an array of N elements by indexing the minimum-value 3 | * element from unsorted portion of array and placing at the start. 4 | * during sorting process, two subarrays of array(N) are maintained, one 5 | * that is sorted, and the other which is unsorted. Through each iteration 6 | * of traverse, the minimum element from the unsorted array is selected 7 | * and placed into sorted array. 8 | */ 9 | async function selectionSort() { 10 | disableUserInput(); 11 | 12 | const column = document.querySelectorAll(".column"); 13 | // traverse array 14 | for (let i = 0; i < column.length - 1; i++) { 15 | // select element to be compared 16 | markColumn(column[i], COLORS.selector); 17 | // create and select minimum index for comparison 18 | // in unsorted portion of array 19 | let min = i; 20 | for (let j = i + 1; j < column.length; j++) { 21 | markColumn(column[j], COLORS.selector); 22 | if (compareColumns(column[min], column[j])) { 23 | // values swapped 24 | min = j; 25 | markColumn(column[min], COLORS.deselector); 26 | await pauseSorter(pauseTime / 25); 27 | } 28 | // 27 - 38 are for visual purposes in site 29 | else { 30 | markColumn(column[j], COLORS.deselector); 31 | await pauseSorter(pauseTime / 25); 32 | } 33 | for (let k = min + 1; k < column.length; k++) { 34 | markColumn(column[k], COLORS.complete); 35 | } 36 | for (let l = i + 1; l < min; l++) { 37 | markColumn(column[l], COLORS.complete); 38 | } 39 | } 40 | // otherwise swap and mark swapped 41 | swapColumns(column[i], column[min]); 42 | markColumn(column[i], COLORS.deselector); 43 | } 44 | // traverse backward and return to original 45 | for (let k = column.length - 1; k >= 0; k--) { 46 | markColumn(column[k], COLORS.complete); 47 | await pauseSorter(100 / newArray.length); 48 | } 49 | 50 | enableUserInput(); 51 | } --------------------------------------------------------------------------------