From 1262484ff117e4fd82994d89c291b2397ce35927 Mon Sep 17 00:00:00 2001
From: Madhu Mohan Reddy <128889553+ymadhumohanreddy@users.noreply.github.com>
Date: Wed, 2 Oct 2024 10:57:22 +0530
Subject: [PATCH] Add files via upload
---
README.md | 63 +++++++++++++++
app.js | 95 ++++++++++++++++++++++
helper.js | 47 +++++++++++
index.html | 81 +++++++++++++++++++
sort-algorithms.js | 162 +++++++++++++++++++++++++++++++++++++
style.css | 197 +++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 645 insertions(+)
create mode 100644 README.md
create mode 100644 app.js
create mode 100644 helper.js
create mode 100644 index.html
create mode 100644 sort-algorithms.js
create mode 100644 style.css
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9f0b6dd
--- /dev/null
+++ b/README.md
@@ -0,0 +1,63 @@
+
+
+---
+
+# Sorting Visualizer
+
+This is a **Sorting Visualizer** project built using **HTML**, **CSS**, and **JavaScript**. It provides a visual representation of different sorting algorithms, allowing users to see how various algorithms operate step-by-step on randomly generated arrays.
+
+## Features
+
+- **Sorting Algorithms**:
+ - Bubble Sort
+ - Selection Sort
+ - Insertion Sort
+ - Merge Sort
+ - Quick Sort
+- **Custom Array Size**: Users can adjust the size of the array.
+- **Speed Control**: Control the visualization speed of the sorting process.
+- **Generate New Array**: Users can generate a new random array to visualize the sorting algorithms on different datasets.
+
+
+
+
+## Project Structure
+
+- **`index.html`**: The main HTML file that defines the structure of the webpage.
+- **`styles.css`**: The CSS file for styling the visualizer, layout, buttons, and overall appearance.
+- **`app.js`**: The core JavaScript file containing the logic for sorting algorithms and the visualization.
+
+## Installation
+
+1. Clone the repository:
+ ```bash
+ git clone https://github.com/yourusername/sorting-visualizer.git
+ ```
+2. Open the project folder:
+ ```bash
+ cd sorting-visualizer
+ ```
+3. Open `index.html` in any modern web browser:
+ ```bash
+ open index.html
+ ```
+
+## Usage
+
+1. Open the `index.html` file in your browser.
+2. Use the controls on the page to:
+ - **Generate a new array**: Click the "Generate New Array" button.
+ - **Choose an algorithm**: Select a sorting algorithm from the dropdown.
+ - **Adjust array size**: Use the slider to change the size of the array.
+ - **Control speed**: Use the speed slider to slow down or speed up the visualization.
+ - **Start sorting**: Click on the "Sort" button to begin visualizing the sorting process.
+
+## Technologies Used
+
+- **HTML**: For structuring the page and elements.
+- **CSS**: For styling the interface and array bars.
+- **JavaScript**: For implementing the sorting algorithms and controlling the visualization.
+
+
+
+---
diff --git a/app.js b/app.js
new file mode 100644
index 0000000..cd103a6
--- /dev/null
+++ b/app.js
@@ -0,0 +1,95 @@
+"use strict";
+const start = async () => {
+ let algoValue = Number(document.querySelector(".algo-menu").value);
+ let speedValue = Number(document.querySelector(".speed-menu").value);
+
+ if (speedValue === 0) {
+ speedValue = 1;
+ }
+ if (algoValue === 0) {
+ alert("No Algorithm Selected");
+ return;
+ }
+
+ let algorithm = new sortAlgorithms(speedValue);
+ if (algoValue === 1) await algorithm.BubbleSort();
+ if (algoValue === 2) await algorithm.SelectionSort();
+ if (algoValue === 3) await algorithm.InsertionSort();
+ if (algoValue === 4) await algorithm.MergeSort();
+ if (algoValue === 5) await algorithm.QuickSort();
+};
+
+const RenderScreen = async () => {
+ let algoValue = Number(document.querySelector(".algo-menu").value);
+ await RenderList();
+};
+
+const RenderList = async () => {
+ let sizeValue = Number(document.querySelector(".size-menu").value);
+ await clearScreen();
+
+ let list = await randomList(sizeValue);
+ const arrayNode = document.querySelector(".array");
+ console.log(arrayNode);
+ console.log(list);
+ for (const element of list) {
+ const node = document.createElement("div");
+ node.className = "cell";
+ node.setAttribute("value", String(element));
+ node.style.height = `${3.8 * element}px`;
+ arrayNode.appendChild(node);
+ }
+};
+
+const RenderArray = async (sorted) => {
+ let sizeValue = Number(document.querySelector(".size-menu").value);
+ await clearScreen();
+
+ let list = await randomList(sizeValue);
+ if (sorted) list.sort((a, b) => a - b);
+
+ const arrayNode = document.querySelector(".array");
+ const divnode = document.createElement("div");
+ divnode.className = "s-array";
+
+ for (const element of list) {
+ const dnode = document.createElement("div");
+ dnode.className = "s-cell";
+ dnode.innerText = element;
+ divnode.appendChild(dnode);
+ }
+ arrayNode.appendChild(divnode);
+};
+
+const randomList = async (Length) => {
+ let list = new Array();
+ let lowerBound = 1;
+ let upperBound = 100;
+
+ for (let counter = 0; counter < Length; ++counter) {
+ let randomNumber = Math.floor(
+ Math.random() * (upperBound - lowerBound + 1) + lowerBound
+ );
+ list.push(parseInt(randomNumber));
+ }
+ return list;
+};
+
+const clearScreen = async () => {
+ document.querySelector(".array").innerHTML = "";
+};
+
+const response = () => {
+ let Navbar = document.querySelector(".navbar");
+ if (Navbar.className === "navbar") {
+ Navbar.className += " responsive";
+ } else {
+ Navbar.className = "navbar";
+ }
+};
+
+document.querySelector(".icon").addEventListener("click", response);
+document.querySelector(".start").addEventListener("click", start);
+document.querySelector(".size-menu").addEventListener("change", RenderScreen);
+document.querySelector(".algo-menu").addEventListener("change", RenderScreen);
+window.onload = RenderScreen;
diff --git a/helper.js b/helper.js
new file mode 100644
index 0000000..49f3b47
--- /dev/null
+++ b/helper.js
@@ -0,0 +1,47 @@
+"use strict";
+class Helper {
+ constructor(time, list = []) {
+ this.time = parseInt(400/time);
+ this.list = list;
+ }
+
+ mark = async (index) => {
+ this.list[index].setAttribute("class", "cell current");
+ }
+
+ markSpl = async (index) => {
+ this.list[index].setAttribute("class", "cell min");
+ }
+
+ unmark = async (index) => {
+ this.list[index].setAttribute("class", "cell");
+ }
+
+ pause = async() => {
+ return new Promise(resolve => {
+ setTimeout(() => {
+ resolve();
+ }, this.time);
+ });
+ }
+
+ compare = async (index1, index2) => {
+ await this.pause();
+ let value1 = Number(this.list[index1].getAttribute("value"));
+ let value2 = Number(this.list[index2].getAttribute("value"));
+ if(value1 > value2) {
+ return true;
+ }
+ return false;
+ }
+
+ swap = async (index1, index2) => {
+ await this.pause();
+ let value1 = this.list[index1].getAttribute("value");
+ let value2 = this.list[index2].getAttribute("value");
+ this.list[index1].setAttribute("value", value2);
+ this.list[index1].style.height = `${3.8*value2}px`;
+ this.list[index2].setAttribute("value", value1);
+ this.list[index2].style.height = `${3.8*value1}px`;
+ }
+};
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..d0edb92
--- /dev/null
+++ b/index.html
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Sorting visualizer
+
+
+
+
+ Sorting visualizer
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sort-algorithms.js b/sort-algorithms.js
new file mode 100644
index 0000000..eec8eaf
--- /dev/null
+++ b/sort-algorithms.js
@@ -0,0 +1,162 @@
+"use strict";
+class sortAlgorithms {
+ constructor(time) {
+ this.list = document.querySelectorAll(".cell");
+ this.size = this.list.length;
+ this.time = time;
+ this.help = new Helper(this.time, this.list);
+ }
+
+ // BUBBLE SORT
+ BubbleSort = async () => {
+ for(let i = 0 ; i < this.size - 1 ; ++i) {
+ for(let j = 0 ; j < this.size - i - 1 ; ++j) {
+ await this.help.mark(j);
+ await this.help.mark(j+1);
+ if(await this.help.compare(j, j+1)) {
+ await this.help.swap(j, j+1);
+ }
+ await this.help.unmark(j);
+ await this.help.unmark(j+1);
+ }
+ this.list[this.size - i - 1].setAttribute("class", "cell done");
+ }
+ this.list[0].setAttribute("class", "cell done");
+ }
+
+ // INSERTION SORT
+ InsertionSort = async () => {
+ for(let i = 0 ; i < this.size - 1 ; ++i) {
+ let j = i;
+ while(j >= 0 && await this.help.compare(j, j+1)) {
+ await this.help.mark(j);
+ await this.help.mark(j+1);
+ await this.help.pause();
+ await this.help.swap(j, j+1);
+ await this.help.unmark(j);
+ await this.help.unmark(j+1);
+ j -= 1;
+ }
+ }
+ for(let counter = 0 ; counter < this.size ; ++counter) {
+ this.list[counter].setAttribute("class", "cell done");
+ }
+ }
+
+ // SELECTION SORT
+ SelectionSort = async () => {
+ for(let i = 0 ; i < this.size ; ++i) {
+ let minIndex = i;
+ for(let j = i ; j < this.size ; ++j) {
+ await this.help.markSpl(minIndex);
+ await this.help.mark(j);
+ if(await this.help.compare(minIndex, j)) {
+ await this.help.unmark(minIndex);
+ minIndex = j;
+ }
+ await this.help.unmark(j);
+ await this.help.markSpl(minIndex);
+ }
+ await this.help.mark(minIndex);
+ await this.help.mark(i);
+ await this.help.pause();
+ await this.help.swap(minIndex, i);
+ await this.help.unmark(minIndex);
+ this.list[i].setAttribute("class", "cell done");
+ }
+ }
+
+ // MERGE SORT
+ MergeSort = async () => {
+ await this.MergeDivider(0, this.size - 1);
+ for(let counter = 0 ; counter < this.size ; ++counter) {
+ this.list[counter].setAttribute("class", "cell done");
+ }
+ }
+
+ MergeDivider = async (start, end) => {
+ if(start < end) {
+ let mid = start + Math.floor((end - start)/2);
+ await this.MergeDivider(start, mid);
+ await this.MergeDivider(mid+1, end);
+ await this.Merge(start, mid, end);
+ }
+ }
+
+ Merge = async (start, mid, end) => {
+ let newList = new Array();
+ let frontcounter = start;
+ let midcounter = mid + 1;
+
+ while(frontcounter <= mid && midcounter <= end) {
+ let fvalue = Number(this.list[frontcounter].getAttribute("value"));
+ let svalue = Number(this.list[midcounter].getAttribute("value"));
+ if(fvalue >= svalue) {
+ newList.push(svalue);
+ ++midcounter;
+ }
+ else {
+ newList.push(fvalue);
+ ++frontcounter;
+ }
+ }
+ while(frontcounter <= mid) {
+ newList.push(Number(this.list[frontcounter].getAttribute("value")));
+ ++frontcounter;
+ }
+ while(midcounter <= end) {
+ newList.push(Number(this.list[midcounter].getAttribute("value")));
+ ++midcounter;
+ }
+
+ for(let c = start ; c <= end ; ++c) {
+ this.list[c].setAttribute("class", "cell current");
+ }
+ for(let c = start, point = 0 ; c <= end && point < newList.length;
+ ++c, ++point) {
+ await this.help.pause();
+ this.list[c].setAttribute("value", newList[point]);
+ this.list[c].style.height = `${3.5*newList[point]}px`;
+ }
+ for(let c = start ; c <= end ; ++c) {
+ this.list[c].setAttribute("class", "cell");
+ }
+ }
+
+ // QUICK SORT
+ QuickSort = async () => {
+ await this.QuickDivider(0, this.size-1);
+ for(let c = 0 ; c < this.size ; ++c) {
+ this.list[c].setAttribute("class", "cell done");
+ }
+ }
+
+ QuickDivider = async (start, end) => {
+ if(start < end) {
+ let pivot = await this.Partition(start, end);
+ await this.QuickDivider(start, pivot-1);
+ await this.QuickDivider(pivot+1, end);
+ }
+ }
+
+ Partition = async (start, end) => {
+ let pivot = this.list[end].getAttribute("value");
+ let prev_index = start - 1;
+
+ await this.help.markSpl(end);
+ for(let c = start ; c < end ; ++c) {
+ let currValue = Number(this.list[c].getAttribute("value"));
+ await this.help.mark(c);
+ if(currValue < pivot) {
+ prev_index += 1;
+ await this.help.mark(prev_index);
+ await this.help.swap(c, prev_index);
+ await this.help.unmark(prev_index);
+ }
+ await this.help.unmark(c);
+ }
+ await this.help.swap(prev_index+1, end);
+ await this.help.unmark(end);
+ return prev_index + 1;
+ }
+};
\ No newline at end of file
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..20ef4e4
--- /dev/null
+++ b/style.css
@@ -0,0 +1,197 @@
+:root {
+ --primary-color:#66b3c1;
+ --secondary-color: #30abc1;
+}
+
+* {
+ /* Below is the standard CSS code one should add to get rid of default margins and padding which most of tge HTML elements have */
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ font-family: "Roboto", sans-serif;
+ user-select: none;
+}
+
+body {
+ position: relative;
+ min-height: 100vh;
+ text-align: center;
+ display: flex;
+ justify-content: space-between;
+ flex-direction: column;
+ align-items: stretch;
+}
+
+/* Title CSS */
+.title {
+ background-color: var(--primary-color);
+ text-align: center;
+ font-size: 1.2em;
+ padding-block: 0.5em;
+ color:#fff;
+ cursor: pointer;
+}
+
+/* Navbar CSS */
+.navbar {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 0.8em;
+ font-size: 16px;
+ min-height: 70px;
+ padding-block: 0.6em;
+ background-color: var(--secondary-color);
+ transition: all 0.5s cubic-bezier(0.645, 0.045, 0.355, 1);
+}
+
+.navbar a {
+ all: unset;
+ cursor: pointer;
+ color: #fff;
+ font-weight: bold;
+ padding: 8px 10px;
+ border-radius: 6px;
+ transition: 0.3s;
+ background-color:#66b3c1;
+}
+
+.navbar a:hover {
+ background-color: transparent;
+}
+
+.navbar #menu {
+ width: fit-content;
+ outline: none;
+ border: none;
+ border-radius: 4px;
+ padding: 6px 8px;
+ background-color: #66b3c1;
+ color: white;
+}
+
+.navbar>.icon {
+ display: none;
+}
+
+#menu,
+#random,
+#start {
+ cursor: pointer;
+}
+
+/* Center css */
+.center {
+ margin: 0 auto;
+ box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px;
+ /* Added shadow to make page border free */
+ height: 420px;
+ width: 410px;
+ max-height: 731px;
+}
+
+.array {
+ display: flex;
+ align-items: flex-start;
+ min-height: 100%;
+ height: 100%;
+ padding: 1rem;
+ flex-direction: row;
+}
+
+.cell {
+ display: flex;
+ align-items: flex-start;
+ flex: 0.5;
+ width: 0.000001%;
+ margin: 1px;
+ background-color: #d6d6d6;
+ resize: horizontal;
+ position: relative;
+ transition: all 0.4s ease-in;
+}
+
+.cell.done {
+ background-color: #9cec5b;
+ border-color: #9cec5b;
+ color: white;
+ transition: all 0.4s ease-out;
+}
+
+.cell.visited {
+ border-color: #6184d8;
+ background-color: #6184d8;
+ color: white;
+ transition: 0.5s;
+}
+
+.cell.current {
+ border-color: #50c5b7;
+ background-color: #50c5b7;
+ color: white;
+ transition: all 0.4s ease-out;
+}
+
+.cell.min {
+ background-color: #ff1493;
+ border-color: #ff1493;
+ color: white;
+ transition: all 0.4s ease-out;
+}
+
+/* Footer CSS */
+.fa.fa-heart {
+ color: #eb2c13;
+}
+
+footer {
+ text-align: center;
+ font-size: 18px;
+ color: #2c3e50;
+ padding: 1.6em;
+}
+
+.footer>p:nth-child(1) {
+ margin-bottom: 0.6em;
+}
+
+.link {
+ text-decoration: none;
+ font-weight: bold;
+ color: #ff5252;
+ font-size: 20px;
+}
+
+@media screen and (max-width: 600px) {
+ .navbar {
+ gap: 0.4em;
+ }
+
+ .title {
+ font-size: 17px;
+ }
+
+ .navbar *,
+ .navbar a {
+ font-size: 14px;
+ }
+
+ .footer {
+ font-size: 18px;
+ }
+
+ a#random {
+ order: 4;
+ }
+
+ a.start {
+ order: 5;
+ }
+}
+
+@media screen and (max-width: 550px) {
+ .center {
+ width: 95%;
+ }
+}
\ No newline at end of file