Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 2 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 47 additions & 0 deletions src/algorithms/sorting/radixSort.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// src/algorithms/sorting/radixSort.js
export function* radixSort(array) {
const arr = [...array];

// Get the maximum number to determine number of digits
const maxNum = Math.max(...arr);
const maxDigits = Math.floor(Math.log10(maxNum)) + 1;

// Helper function to get digit at a specific place
const getDigit = (num, place) => Math.floor(num / Math.pow(10, place)) % 10;

// Counting sort for each digit position
for (let place = 0; place < maxDigits; place++) {
const buckets = Array.from({ length: 10 }, () => []);

// Yield to show current digit pass
yield { type: "digitPassStart", place };

// Place each number in corresponding bucket
for (let i = 0; i < arr.length; i++) {
const digit = getDigit(arr[i], place);
buckets[digit].push(arr[i]);

yield { type: "bucket", digit, value: arr[i], array: [...arr] };
}

// Combine buckets back into array
let index = 0;
for (let b = 0; b < 10; b++) {
for (let value of buckets[b]) {
arr[index++] = value;
yield { type: "rebuild", array: [...arr], bucket: b, value };
}
}

// Yield after completing sorting by current digit
yield { type: "digitPassEnd", place, array: [...arr] };
}

// Mark all elements as sorted
for (let i = 0; i < arr.length; i++) {
yield { type: "sorted", index: i };
}

// Final done state
yield { type: "done", array: arr };
}
72 changes: 72 additions & 0 deletions src/components/sorting/RadixSortVisualizer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React from "react";

const COLORS = {
default: "bg-blue-500 shadow-[0_0_10px_#3b82f6]",
comparing: "bg-yellow-400 shadow-[0_0_12px_#facc15]",
bucket: "bg-purple-500 shadow-[0_0_12px_#a855f7]",
swap: "bg-red-500 shadow-[0_0_12px_#ef4444]",
sorted: "bg-green-500 shadow-[0_0_12px_#22c55e]",
};

export default function RadixSortVisualizer({ array, highlight }) {
const maxValue = Math.max(...array, 1);
const containerHeight = 288; // matches h-72

return (
<div className="flex flex-col items-center mt-10 space-y-6">
{/* Main Array Display */}
<div className="flex items-end justify-center space-x-2 h-72 transition-all duration-500">
{array.map((value, idx) => {
let color = COLORS.default;

if (highlight?.type === "compare" && highlight.indices?.includes(idx))
color = COLORS.comparing;
if (highlight?.type === "bucket" && highlight.indices?.includes(idx))
color = COLORS.bucket;
if (highlight?.type === "swap" && highlight.indices?.includes(idx))
color = COLORS.swap;
if (highlight?.type === "sorted" && highlight.indices?.includes(idx))
color = COLORS.sorted;

const height = Math.max((value / maxValue) * containerHeight, 15);

return (
<div
key={idx}
className={`${color} w-6 transition-all duration-300 rounded-t-md`}
style={{ height: `${height}px` }}
></div>
);
})}
</div>

{/* Current Digit / Pass Info */}
{highlight?.digit !== undefined && (
<div className="text-center text-lg font-medium text-gray-300">
Processing Digit Place:{" "}
<span className="text-yellow-400">{highlight.digit}</span>
</div>
)}

{/* Buckets Visualization */}
{highlight?.buckets && (
<div className="grid grid-cols-10 gap-4 text-center">
{highlight.buckets.map((bucket, i) => (
<div key={i} className="flex flex-col items-center">
<div className="text-gray-300 text-sm mb-2">Bucket {i}</div>
<div className="flex space-x-1">
{bucket.map((val, j) => (
<div
key={j}
className={`${COLORS.bucket} w-4 h-4 rounded-sm`}
title={val}
></div>
))}
</div>
</div>
))}
</div>
)}
</div>
);
}
79 changes: 79 additions & 0 deletions src/pages/sorting/RadixSort.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { useState } from "react";
import { Toaster } from "react-hot-toast";
import RadixSortVisualizer from "../../components/sorting/RadixSortVisualizer";
import { radixSort } from "../../algorithms/sorting/radixSort";

export default function RadixSort() {
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 = radixSort(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) && n >= 0); // only non-negative numbers
setArray(numbers);
};

return (
<div className="min-h-screen bg-black text-gray-200 flex flex-col items-center p-6">
<Toaster position="top-center" />
<h1 className="text-4xl font-extrabold mb-8 text-cyan-400 drop-shadow-lg">
Radix Sort Visualizer
</h1>

<input
type="text"
value={input}
onChange={handleInput}
placeholder="Enter non-negative numbers separated by commas"
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"
/>

<div className="space-x-4 mt-6">
<button
onClick={handleStart}
disabled={isRunning}
className={`${isRunning
? "bg-cyan-700 text-gray-300 cursor-not-allowed"
: "bg-cyan-600 hover:bg-cyan-500"
} px-6 py-2 rounded-lg text-white font-semibold shadow-md transition-all duration-300`}
>
{isRunning ? "Sorting..." : "Start Visualization"}
</button>
<button
onClick={handleReset}
className="bg-gray-700 hover:bg-gray-600 px-6 py-2 rounded-lg text-white font-semibold shadow-md transition-all duration-300"
>
Reset
</button>
</div>

<div className="mt-12">
<RadixSortVisualizer array={array} highlight={highlight} />
</div>
</div>
);
}
8 changes: 6 additions & 2 deletions src/pages/sorting/SortingPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import BubbleSort from "./BubbleSort";
import InsertionSort from "./InsertionSort";
import QuickSort from "./QuickSort";
import MergeSort from "./MergeSort";
import RadixSort from "./RadixSort";

export default function SortingPage() {
const [selectedAlgo, setSelectedAlgo] = useState("");
Expand All @@ -13,8 +14,8 @@ export default function SortingPage() {
switch (selectedAlgo) {
case "selection":
return <SelectionSort />;
case "insertion":
return <InsertionSort />;
case "insertion":
return <InsertionSort />;
// You can add more later like:
case "bubble":
return <BubbleSort />;
Expand All @@ -23,6 +24,8 @@ export default function SortingPage() {
// case "merge": return <MergeSort />;
case "merge":
return <MergeSort />;
case "radix":
return <RadixSort />
default:
return (
<div className="text-gray-400 text-lg mt-20 text-center">
Expand Down Expand Up @@ -52,6 +55,7 @@ export default function SortingPage() {
<option value="insertion">Insertion Sort</option>
<option value="quick">Quick Sort</option>
<option value="merge">Merge Sort</option>
<option value="radix">Radix Sort</option>
</select>

<button
Expand Down
Loading