Skip to content
Closed
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
2 changes: 2 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
// import UnionFindPage from "../src/pages/graph/UnionFind.jsx"; // ✅ Import Union-Find Page
import SortingPage from "./pages/sorting/SortingPage";
import GraphPage from "./pages/graph/GraphPage";
import Searchingpage from "./pages/searching/searchingPage";
import Homepage from "./pages/Homepage.jsx";

function App() {
Expand All @@ -12,6 +13,7 @@ function App() {
<Route path="/" element={<Homepage />} />
{/* <Route path="/graph/union-find" element={<UnionFindPage />} /> */}
<Route path="/sorting" element={<SortingPage />} />
<Route path="/searching" element={<Searchingpage />} />
<Route path="/graph" element={<GraphPage />} />
</Routes>
</Router>
Expand Down
38 changes: 38 additions & 0 deletions src/algorithms/searching/LinearSearch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* A generator function that performs Linear Search and yields visualization steps.
* @param {number[]} array - The array to search through.
* @param {number} target - The value to find.
* @yields {{highlightIndex: number | null, foundIndex: number | null, message?: string}}
*/
export function* linearSearch(array, target) {
const targetNumber = parseInt(target); // Ensure target is a number
let foundIndex = null;

// Iterate through the array
for (let i = 0; i < array.length; i++) {
// 1. Yield the current index being compared (yellow highlight)
yield {
highlightIndex: i,
foundIndex: foundIndex
};

// 2. Check for the target
if (array[i] === targetNumber) {
foundIndex = i;
// Target found, yield the final state (green) and return
yield {
highlightIndex: i,
foundIndex: foundIndex,
message: `Success! Found target ${targetNumber} at index ${i}`
};
return; // Stop the generator
}
}

// If the loop finishes without finding the target
yield {
highlightIndex: null, // Clear highlight
foundIndex: null, // Not found
message: `Target ${targetNumber} was not found in the array.`
};
}
46 changes: 46 additions & 0 deletions src/components/searching/LinearSearchVisualizer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from "react";

// Updated colors for searching visualization
const COLORS = {
default: "bg-blue-500 shadow-[0_0_10px_#3b82f6]", // Default bar color
comparing: "bg-yellow-400 shadow-[0_0_12px_#facc15]", // Element currently being checked
found: "bg-green-500 shadow-[0_0_12px_#22c55e]", // Target element found
miss: "bg-red-500 shadow-[0_0_12px_#ef4444]", // Optional: To highlight elements that were skipped (e.g., in Binary Search)
};

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

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

// 1. Check if the element has been found (Highest priority for the final result)
if (foundIndex === idx) {
color = COLORS.found;
}
// 2. Check if the element is currently being compared
else if (highlightIndex === idx) {
color = COLORS.comparing;
}

// Normalize height relative to the maximum value
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>
);
}
132 changes: 132 additions & 0 deletions src/pages/searching/linearSearch.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import React, { useState } from "react";
import { Toaster, toast } from "react-hot-toast";
import LinearSearchVisualizer from "../../components/searching/LinearSearchVisualizer";
import { linearSearch } from "../../algorithms/searching/linearSearch";


export default function LinearSearch() {
const [array, setArray] = useState([]);
const [input, setInput] = useState("");

// --- SEARCH STATES ---
const [target, setTarget] = useState(null);
const [highlightIndex, setHighlightIndex] = useState(null);
const [foundIndex, setFoundIndex] = useState(null);
// ---------------------

const [isRunning, setIsRunning] = useState(false);

const handleStart = async () => {
if (isRunning || array.length === 0 || isNaN(parseInt(target))) {
toast.error("Please ensure the array and target are valid.");
return;
}

setIsRunning(true);
setHighlightIndex(null);
setFoundIndex(null);

const targetNumber = parseInt(target);

// Pass the array AND the target to the generator
const gen = linearSearch(array, targetNumber);

for (let step of gen) {
// Update search-specific states
setHighlightIndex(step.highlightIndex);
setFoundIndex(step.foundIndex);

if (step.message) {
if (step.foundIndex !== null) {
toast.success(step.message);
} else {
toast.error(step.message);
}
}

// Wait for 500ms for visualization (adjust this speed later)
await new Promise((r) => setTimeout(r, 500));
}

setIsRunning(false);
};

const handleReset = () => {
setArray([]);
setInput("");
setTarget(50); // Reset target input
setHighlightIndex(null);
setFoundIndex(null);
setIsRunning(false);
};

const handleInput = (e) => {
setInput(e.target.value);
const numbers = e.target.value
.split(",")
.map((n) => parseInt(n.trim()))
.filter((n) => !isNaN(n));
setArray(numbers);
};

const handleTargetChange = (e) => {
setTarget(e.target.value);
};

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-indigo-400 drop-shadow-lg">
Linear Search Visualizer
</h1>

{/* INPUTS: ARRAY AND TARGET */}
<div className="flex flex-col md:flex-row space-y-4 md:space-y-0 md:space-x-4 mb-6">
<input
type="text"
value={input}
onChange={handleInput}
placeholder="Enter array (e.g., 10,20,50,40)"
className="border-2 border-gray-400 bg-gray-900 text-green-200 rounded-lg p-3 w-80 text-center shadow-lg focus:ring-2 focus:ring-blue-500 outline-none"
/>
<input
type="number"
value={target}
onChange={handleTargetChange}
placeholder="Target Value"
className="border-2 border-gray-300 bg-gray-900 text-yellow-200 rounded-lg p-3 w-40 text-center shadow-lg focus:ring-2 focus:ring-blue-500 outline-none"
/>
</div>

<div className="space-x-4 mt-6">
<button
onClick={handleStart}
disabled={isRunning || array.length === 0}
className={`${
isRunning || array.length === 0
? "bg-indigo-500 text-white cursor-not-allowed"
: "bg-indigo-500 hover:bg-indigo-900"
} px-6 py-2 rounded-lg text-white font-semibold shadow-md transition-all duration-300`}
>
{isRunning ? "Searching..." : "Start Linear Search"}
</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-15">
{/* USE THE NEW VISUALIZER AND PASS SEARCH STATES */}
<LinearSearchVisualizer
array={array}
highlightIndex={highlightIndex}
foundIndex={foundIndex}
/>
</div>

</div>
);
}
61 changes: 61 additions & 0 deletions src/pages/searching/searchingPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// src/pages/SortingPage.jsx
import React, { useState } from "react";
import LinearSearch from "./linearSearch";

export default function SortingPage() {
const [selectedAlgo, setSelectedAlgo] = useState("");

const renderAlgorithm = () => {
switch (selectedAlgo) {
case "LinearSearch":
return <LinearSearch />;

default:
return (
<div className="text-gray-400 text-lg mt-20 text-center">
Select an algorithm to visualize 👆
</div>
);
}
};

return (
<div className="flex h-screen bg-black text-white">
{/* Left Sidebar */}
<div className="w-64 bg-[#0f172a] p-6">
<h2 className="text-xl font-bold mb-6 text-indigo-400">
Searching Panel
</h2>

<label className="block mb-2 text-sm">Algorithm:</label>
<select
value={selectedAlgo}
onChange={(e) => setSelectedAlgo(e.target.value)}
className="w-full p-2 rounded bg-[#1e293b] text-white border border-gray-600"
>
<option value="">Select Algorithm</option>
<option value="LinearSearch">LinearSearch</option>
</select>

<button
onClick={() => setSelectedAlgo("")}
className="w-full mt-4 py-2 bg-gray-600 hover:bg-gray-700 rounded"
>
Reset
</button>

<a
href="/"
className="inline-block mt-10 text-indigo-400 hover:underline text-sm"
>
← Back to Home
</a>
</div>

{/* Right Visualization Area */}
<div className="flex-1 flex justify-center items-center">
{renderAlgorithm()}
</div>
</div>
);
}