Skip to content

Commit ae5f506

Browse files
committed
RadixSortVisualizerAdded
1 parent ccaeb96 commit ae5f506

File tree

5 files changed

+206
-19
lines changed

5 files changed

+206
-19
lines changed

package-lock.json

Lines changed: 2 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// src/algorithms/sorting/radixSort.js
2+
export function* radixSort(array) {
3+
const arr = [...array];
4+
5+
// Get the maximum number to determine number of digits
6+
const maxNum = Math.max(...arr);
7+
const maxDigits = Math.floor(Math.log10(maxNum)) + 1;
8+
9+
// Helper function to get digit at a specific place
10+
const getDigit = (num, place) => Math.floor(num / Math.pow(10, place)) % 10;
11+
12+
// Counting sort for each digit position
13+
for (let place = 0; place < maxDigits; place++) {
14+
const buckets = Array.from({ length: 10 }, () => []);
15+
16+
// Yield to show current digit pass
17+
yield { type: "digitPassStart", place };
18+
19+
// Place each number in corresponding bucket
20+
for (let i = 0; i < arr.length; i++) {
21+
const digit = getDigit(arr[i], place);
22+
buckets[digit].push(arr[i]);
23+
24+
yield { type: "bucket", digit, value: arr[i], array: [...arr] };
25+
}
26+
27+
// Combine buckets back into array
28+
let index = 0;
29+
for (let b = 0; b < 10; b++) {
30+
for (let value of buckets[b]) {
31+
arr[index++] = value;
32+
yield { type: "rebuild", array: [...arr], bucket: b, value };
33+
}
34+
}
35+
36+
// Yield after completing sorting by current digit
37+
yield { type: "digitPassEnd", place, array: [...arr] };
38+
}
39+
40+
// Mark all elements as sorted
41+
for (let i = 0; i < arr.length; i++) {
42+
yield { type: "sorted", index: i };
43+
}
44+
45+
// Final done state
46+
yield { type: "done", array: arr };
47+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import React from "react";
2+
3+
const COLORS = {
4+
default: "bg-blue-500 shadow-[0_0_10px_#3b82f6]",
5+
comparing: "bg-yellow-400 shadow-[0_0_12px_#facc15]",
6+
bucket: "bg-purple-500 shadow-[0_0_12px_#a855f7]",
7+
swap: "bg-red-500 shadow-[0_0_12px_#ef4444]",
8+
sorted: "bg-green-500 shadow-[0_0_12px_#22c55e]",
9+
};
10+
11+
export default function RadixSortVisualizer({ array, highlight }) {
12+
const maxValue = Math.max(...array, 1);
13+
const containerHeight = 288; // matches h-72
14+
15+
return (
16+
<div className="flex flex-col items-center mt-10 space-y-6">
17+
{/* Main Array Display */}
18+
<div className="flex items-end justify-center space-x-2 h-72 transition-all duration-500">
19+
{array.map((value, idx) => {
20+
let color = COLORS.default;
21+
22+
if (highlight?.type === "compare" && highlight.indices?.includes(idx))
23+
color = COLORS.comparing;
24+
if (highlight?.type === "bucket" && highlight.indices?.includes(idx))
25+
color = COLORS.bucket;
26+
if (highlight?.type === "swap" && highlight.indices?.includes(idx))
27+
color = COLORS.swap;
28+
if (highlight?.type === "sorted" && highlight.indices?.includes(idx))
29+
color = COLORS.sorted;
30+
31+
const height = Math.max((value / maxValue) * containerHeight, 15);
32+
33+
return (
34+
<div
35+
key={idx}
36+
className={`${color} w-6 transition-all duration-300 rounded-t-md`}
37+
style={{ height: `${height}px` }}
38+
></div>
39+
);
40+
})}
41+
</div>
42+
43+
{/* Current Digit / Pass Info */}
44+
{highlight?.digit !== undefined && (
45+
<div className="text-center text-lg font-medium text-gray-300">
46+
Processing Digit Place:{" "}
47+
<span className="text-yellow-400">{highlight.digit}</span>
48+
</div>
49+
)}
50+
51+
{/* Buckets Visualization */}
52+
{highlight?.buckets && (
53+
<div className="grid grid-cols-10 gap-4 text-center">
54+
{highlight.buckets.map((bucket, i) => (
55+
<div key={i} className="flex flex-col items-center">
56+
<div className="text-gray-300 text-sm mb-2">Bucket {i}</div>
57+
<div className="flex space-x-1">
58+
{bucket.map((val, j) => (
59+
<div
60+
key={j}
61+
className={`${COLORS.bucket} w-4 h-4 rounded-sm`}
62+
title={val}
63+
></div>
64+
))}
65+
</div>
66+
</div>
67+
))}
68+
</div>
69+
)}
70+
</div>
71+
);
72+
}

src/pages/sorting/RadixSort.jsx

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import React, { useState } from "react";
2+
import { Toaster } from "react-hot-toast";
3+
import RadixSortVisualizer from "../../components/sorting/RadixSortVisualizer";
4+
import { radixSort } from "../../algorithms/sorting/radixSort";
5+
6+
export default function RadixSort() {
7+
const [array, setArray] = useState([]);
8+
const [input, setInput] = useState("");
9+
const [highlight, setHighlight] = useState(null);
10+
const [isRunning, setIsRunning] = useState(false);
11+
12+
const handleStart = async () => {
13+
if (isRunning || array.length === 0) return;
14+
setIsRunning(true);
15+
const gen = radixSort(array);
16+
for (let step of gen) {
17+
setHighlight(step);
18+
if (step.array) setArray([...step.array]);
19+
await new Promise((r) => setTimeout(r, 500));
20+
}
21+
setHighlight({ type: "done" });
22+
setIsRunning(false);
23+
};
24+
25+
const handleReset = () => {
26+
setArray([]);
27+
setInput("");
28+
setHighlight(null);
29+
};
30+
31+
const handleInput = (e) => {
32+
setInput(e.target.value);
33+
const numbers = e.target.value
34+
.split(",")
35+
.map((n) => parseInt(n.trim()))
36+
.filter((n) => !isNaN(n) && n >= 0); // only non-negative numbers
37+
setArray(numbers);
38+
};
39+
40+
return (
41+
<div className="min-h-screen bg-black text-gray-200 flex flex-col items-center p-6">
42+
<Toaster position="top-center" />
43+
<h1 className="text-4xl font-extrabold mb-8 text-cyan-400 drop-shadow-lg">
44+
Radix Sort Visualizer
45+
</h1>
46+
47+
<input
48+
type="text"
49+
value={input}
50+
onChange={handleInput}
51+
placeholder="Enter non-negative numbers separated by commas"
52+
className="border-2 border-cyan-500 bg-gray-900 text-cyan-200 rounded-lg p-3 w-96 text-center shadow-lg focus:ring-2 focus:ring-cyan-400 outline-none"
53+
/>
54+
55+
<div className="space-x-4 mt-6">
56+
<button
57+
onClick={handleStart}
58+
disabled={isRunning}
59+
className={`${isRunning
60+
? "bg-cyan-700 text-gray-300 cursor-not-allowed"
61+
: "bg-cyan-600 hover:bg-cyan-500"
62+
} px-6 py-2 rounded-lg text-white font-semibold shadow-md transition-all duration-300`}
63+
>
64+
{isRunning ? "Sorting..." : "Start Visualization"}
65+
</button>
66+
<button
67+
onClick={handleReset}
68+
className="bg-gray-700 hover:bg-gray-600 px-6 py-2 rounded-lg text-white font-semibold shadow-md transition-all duration-300"
69+
>
70+
Reset
71+
</button>
72+
</div>
73+
74+
<div className="mt-12">
75+
<RadixSortVisualizer array={array} highlight={highlight} />
76+
</div>
77+
</div>
78+
);
79+
}

src/pages/sorting/SortingPage.jsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import BubbleSort from "./BubbleSort";
55
import InsertionSort from "./InsertionSort";
66
import QuickSort from "./QuickSort";
77
import MergeSort from "./MergeSort";
8+
import RadixSort from "./RadixSort";
89

910
export default function SortingPage() {
1011
const [selectedAlgo, setSelectedAlgo] = useState("");
@@ -13,8 +14,8 @@ export default function SortingPage() {
1314
switch (selectedAlgo) {
1415
case "selection":
1516
return <SelectionSort />;
16-
case "insertion":
17-
return <InsertionSort />;
17+
case "insertion":
18+
return <InsertionSort />;
1819
// You can add more later like:
1920
case "bubble":
2021
return <BubbleSort />;
@@ -23,6 +24,8 @@ export default function SortingPage() {
2324
// case "merge": return <MergeSort />;
2425
case "merge":
2526
return <MergeSort />;
27+
case "radix":
28+
return <RadixSort />
2629
default:
2730
return (
2831
<div className="text-gray-400 text-lg mt-20 text-center">
@@ -52,6 +55,7 @@ export default function SortingPage() {
5255
<option value="insertion">Insertion Sort</option>
5356
<option value="quick">Quick Sort</option>
5457
<option value="merge">Merge Sort</option>
58+
<option value="radix">Radix Sort</option>
5559
</select>
5660

5761
<button

0 commit comments

Comments
 (0)