├── .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 | Bubble Sort Algorithm
8 | Insertion Sort Algorithm
9 | Selection Sort Algorithm
10 | Merge Sort Algorithm
11 | Quick Sort Algorithm
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 |
34 |
Sorting Visualization Tool
35 |
36 |
37 |
38 |
39 |
Array Size
40 |
8
41 |
42 |
150
43 |
44 |
45 |
46 |
47 | Bubble Sort
48 | Insertion Sort
49 | Selection Sort
50 | Merge Sort
51 | Quick Sort
52 |
53 |
54 |
55 |
56 |
Sort Speed
57 |
-
58 |
59 |
+
60 |
61 |
62 |
63 |
72 |
73 |
74 | Generate Array
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 | }
--------------------------------------------------------------------------------