diff --git a/src/algorithms/sorting/bubbleSort.js b/src/algorithms/sorting/bubbleSort.js new file mode 100644 index 0000000..71fe43d --- /dev/null +++ b/src/algorithms/sorting/bubbleSort.js @@ -0,0 +1,24 @@ +// src/algorithms/sorting/bubbleSort.js +export function* bubbleSort(array) { + const arr = [...array]; + const n = arr.length; + + // Standard bubble sort with generator events + for (let i = 0; i < n - 1; i++) { + // After each pass, the largest element of the unsorted portion bubbles to position n-1-i + for (let j = 0; j < n - 1 - i; j++) { + // compare pair (j, j+1) + yield { type: "compare", indices: [j, j + 1] }; + + if (arr[j] > arr[j + 1]) { + [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; + yield { type: "swap", indices: [j, j + 1], array: [...arr] }; + } + } + + // mark the settled position at the end of this pass + yield { type: "min", index: n - 1 - i }; + } + + yield { type: "done", array: arr }; +} \ No newline at end of file diff --git a/src/components/sorting/BubbleSortVisualizer.jsx b/src/components/sorting/BubbleSortVisualizer.jsx new file mode 100644 index 0000000..3b7c24f --- /dev/null +++ b/src/components/sorting/BubbleSortVisualizer.jsx @@ -0,0 +1,38 @@ +import React from "react"; + +const COLORS = { + default: "bg-blue-500 shadow-[0_0_10px_#3b82f6]", + comparing: "bg-yellow-400 shadow-[0_0_12px_#facc15]", + min: "bg-green-500 shadow-[0_0_12px_#22c55e]", + swap: "bg-red-500 shadow-[0_0_12px_#ef4444]", +}; + +export default function BubbleSortVisualizer({ array, highlight }) { + const maxValue = Math.max(...array, 1); // Avoid division by zero + const containerHeight = 288; // px (matches h-72) + + return ( +
+ {array.map((value, idx) => { + let color = COLORS.default; + if (highlight?.type === "compare" && highlight.indices?.includes(idx)) + color = COLORS.comparing; + if (highlight?.type === "min" && highlight.index === idx) + color = COLORS.min; + if (highlight?.type === "swap" && highlight.indices?.includes(idx)) + color = COLORS.swap; + + // Normalize height relative to the maximum value + const height = Math.max((value / maxValue) * containerHeight, 15); // minimum 15px for visibility + + return ( +
+ ); + })} +
+ ); +} \ No newline at end of file diff --git a/src/pages/sorting/BubbleSort.jsx b/src/pages/sorting/BubbleSort.jsx new file mode 100644 index 0000000..261bba0 --- /dev/null +++ b/src/pages/sorting/BubbleSort.jsx @@ -0,0 +1,83 @@ +import React, { useState } from "react"; +import { Toaster } from "react-hot-toast"; +import BubbleSortVisualizer from "../../components/sorting/BubbleSortVisualizer"; +import { bubbleSort } from "../../algorithms/sorting/bubbleSort"; + +export default function BubbleSort() { + const [array, setArray] = useState([]); + const [input, setInput] = useState(""); + const [highlight, setHighlight] = useState(null); + const [isRunning, setIsRunning] = useState(false); + + const handleStart = async () => { + if (isRunning || array.length === 0) return; + setIsRunning(true); + + const gen = bubbleSort(array); + for (let step of gen) { + setHighlight(step); + if (step.array) setArray([...step.array]); + await new Promise((r) => setTimeout(r, 500)); + } + + setHighlight({ type: "done" }); + setIsRunning(false); + }; + + const handleReset = () => { + setArray([]); + setInput(""); + setHighlight(null); + }; + + const handleInput = (e) => { + setInput(e.target.value); + const numbers = e.target.value + .split(",") + .map((n) => parseInt(n.trim())) + .filter((n) => !isNaN(n)); + setArray(numbers); + }; + + return ( +
+ +

+ Bubble Sort Visualizer +

+ + + +
+ + +
+ +
+ +
+ +
+ ); +} \ No newline at end of file diff --git a/src/pages/sorting/SortingPage.jsx b/src/pages/sorting/SortingPage.jsx index 8d8ab88..6422058 100644 --- a/src/pages/sorting/SortingPage.jsx +++ b/src/pages/sorting/SortingPage.jsx @@ -1,6 +1,7 @@ // src/pages/SortingPage.jsx import React, { useState } from "react"; import SelectionSort from "./SelectionSort"; +import BubbleSort from "./BubbleSort"; import InsertionSort from "./InsertionSort"; export default function SortingPage() { @@ -13,7 +14,8 @@ export default function SortingPage() { case "insertion": return ; // You can add more later like: - // case "bubble": return ; + case "bubble": + return ; // case "merge": return ; default: return ( @@ -40,6 +42,7 @@ export default function SortingPage() { > +