Skip to content

Commit 766246c

Browse files
committed
feat: Implement linear search
Binary search will be implemented in further commits
1 parent e696d27 commit 766246c

File tree

5 files changed

+279
-0
lines changed

5 files changed

+279
-0
lines changed

src/App.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
33
// import UnionFindPage from "../src/pages/graph/UnionFind.jsx"; // ✅ Import Union-Find Page
44
import SortingPage from "./pages/sorting/SortingPage";
55
import GraphPage from "./pages/graph/GraphPage";
6+
import Searchingpage from "./pages/searching/searchingPage";
67
import Homepage from "./pages/Homepage.jsx";
78

89
function App() {
@@ -12,6 +13,7 @@ function App() {
1213
<Route path="/" element={<Homepage />} />
1314
{/* <Route path="/graph/union-find" element={<UnionFindPage />} /> */}
1415
<Route path="/sorting" element={<SortingPage />} />
16+
<Route path="/searching" element={<Searchingpage />} />
1517
<Route path="/graph" element={<GraphPage />} />
1618
</Routes>
1719
</Router>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* A generator function that performs Linear Search and yields visualization steps.
3+
* @param {number[]} array - The array to search through.
4+
* @param {number} target - The value to find.
5+
* @yields {{highlightIndex: number | null, foundIndex: number | null, message?: string}}
6+
*/
7+
export function* linearSearch(array, target) {
8+
const targetNumber = parseInt(target); // Ensure target is a number
9+
let foundIndex = null;
10+
11+
// Iterate through the array
12+
for (let i = 0; i < array.length; i++) {
13+
// 1. Yield the current index being compared (yellow highlight)
14+
yield {
15+
highlightIndex: i,
16+
foundIndex: foundIndex
17+
};
18+
19+
// 2. Check for the target
20+
if (array[i] === targetNumber) {
21+
foundIndex = i;
22+
// Target found, yield the final state (green) and return
23+
yield {
24+
highlightIndex: i,
25+
foundIndex: foundIndex,
26+
message: `Success! Found target ${targetNumber} at index ${i}`
27+
};
28+
return; // Stop the generator
29+
}
30+
}
31+
32+
// If the loop finishes without finding the target
33+
yield {
34+
highlightIndex: null, // Clear highlight
35+
foundIndex: null, // Not found
36+
message: `Target ${targetNumber} was not found in the array.`
37+
};
38+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import React from "react";
2+
3+
// Updated colors for searching visualization
4+
const COLORS = {
5+
default: "bg-blue-500 shadow-[0_0_10px_#3b82f6]", // Default bar color
6+
comparing: "bg-yellow-400 shadow-[0_0_12px_#facc15]", // Element currently being checked
7+
found: "bg-green-500 shadow-[0_0_12px_#22c55e]", // Target element found
8+
miss: "bg-red-500 shadow-[0_0_12px_#ef4444]", // Optional: To highlight elements that were skipped (e.g., in Binary Search)
9+
};
10+
11+
export default function LinearSearchVisualizer({
12+
array,
13+
highlightIndex,
14+
foundIndex
15+
}) {
16+
const maxValue = Math.max(...array, 1);
17+
const containerHeight = 288; // px (matches h-72)
18+
19+
return (
20+
<div className="flex items-end justify-center space-x-2 h-72 mt-10 transition-all duration-500">
21+
{array.map((value, idx) => {
22+
let color = COLORS.default;
23+
24+
// 1. Check if the element has been found (Highest priority for the final result)
25+
if (foundIndex === idx) {
26+
color = COLORS.found;
27+
}
28+
// 2. Check if the element is currently being compared
29+
else if (highlightIndex === idx) {
30+
color = COLORS.comparing;
31+
}
32+
33+
// Normalize height relative to the maximum value
34+
const height = Math.max((value / maxValue) * containerHeight, 15);
35+
36+
return (
37+
<div
38+
key={idx}
39+
className={`${color} w-6 transition-all duration-300 rounded-t-md`}
40+
style={{ height: `${height}px` }}
41+
></div>
42+
);
43+
})}
44+
</div>
45+
);
46+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import React, { useState } from "react";
2+
import { Toaster, toast } from "react-hot-toast";
3+
import LinearSearchVisualizer from "../../components/searching/LinearSearchVisualizer";
4+
import { linearSearch } from "../../algorithms/searching/linearSearch";
5+
6+
7+
export default function LinearSearch() {
8+
const [array, setArray] = useState([]);
9+
const [input, setInput] = useState("");
10+
11+
// --- SEARCH STATES ---
12+
const [target, setTarget] = useState(null);
13+
const [highlightIndex, setHighlightIndex] = useState(null);
14+
const [foundIndex, setFoundIndex] = useState(null);
15+
// ---------------------
16+
17+
const [isRunning, setIsRunning] = useState(false);
18+
19+
const handleStart = async () => {
20+
if (isRunning || array.length === 0 || isNaN(parseInt(target))) {
21+
toast.error("Please ensure the array and target are valid.");
22+
return;
23+
}
24+
25+
setIsRunning(true);
26+
setHighlightIndex(null);
27+
setFoundIndex(null);
28+
29+
const targetNumber = parseInt(target);
30+
31+
// Pass the array AND the target to the generator
32+
const gen = linearSearch(array, targetNumber);
33+
34+
for (let step of gen) {
35+
// Update search-specific states
36+
setHighlightIndex(step.highlightIndex);
37+
setFoundIndex(step.foundIndex);
38+
39+
if (step.message) {
40+
if (step.foundIndex !== null) {
41+
toast.success(step.message);
42+
} else {
43+
toast.error(step.message);
44+
}
45+
}
46+
47+
// Wait for 500ms for visualization (adjust this speed later)
48+
await new Promise((r) => setTimeout(r, 500));
49+
}
50+
51+
setIsRunning(false);
52+
};
53+
54+
const handleReset = () => {
55+
setArray([]);
56+
setInput("");
57+
setTarget(50); // Reset target input
58+
setHighlightIndex(null);
59+
setFoundIndex(null);
60+
setIsRunning(false);
61+
};
62+
63+
const handleInput = (e) => {
64+
setInput(e.target.value);
65+
const numbers = e.target.value
66+
.split(",")
67+
.map((n) => parseInt(n.trim()))
68+
.filter((n) => !isNaN(n));
69+
setArray(numbers);
70+
};
71+
72+
const handleTargetChange = (e) => {
73+
setTarget(e.target.value);
74+
};
75+
76+
return (
77+
<div className="min-h-screen bg-black text-gray-200 flex flex-col items-center p-6">
78+
<Toaster position="top-center" />
79+
<h1 className="text-4xl font-extrabold mb-8 text-indigo-400 drop-shadow-lg">
80+
Linear Search Visualizer
81+
</h1>
82+
83+
{/* INPUTS: ARRAY AND TARGET */}
84+
<div className="flex flex-col md:flex-row space-y-4 md:space-y-0 md:space-x-4 mb-6">
85+
<input
86+
type="text"
87+
value={input}
88+
onChange={handleInput}
89+
placeholder="Enter array (e.g., 10,20,50,40)"
90+
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"
91+
/>
92+
<input
93+
type="number"
94+
value={target}
95+
onChange={handleTargetChange}
96+
placeholder="Target Value"
97+
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"
98+
/>
99+
</div>
100+
101+
<div className="space-x-4 mt-6">
102+
<button
103+
onClick={handleStart}
104+
disabled={isRunning || array.length === 0}
105+
className={`${
106+
isRunning || array.length === 0
107+
? "bg-indigo-500 text-white cursor-not-allowed"
108+
: "bg-indigo-500 hover:bg-indigo-900"
109+
} px-6 py-2 rounded-lg text-white font-semibold shadow-md transition-all duration-300`}
110+
>
111+
{isRunning ? "Searching..." : "Start Linear Search"}
112+
</button>
113+
<button
114+
onClick={handleReset}
115+
className="bg-gray-700 hover:bg-gray-600 px-6 py-2 rounded-lg text-white font-semibold shadow-md transition-all duration-300"
116+
>
117+
Reset
118+
</button>
119+
</div>
120+
121+
<div className="mt-15">
122+
{/* USE THE NEW VISUALIZER AND PASS SEARCH STATES */}
123+
<LinearSearchVisualizer
124+
array={array}
125+
highlightIndex={highlightIndex}
126+
foundIndex={foundIndex}
127+
/>
128+
</div>
129+
130+
</div>
131+
);
132+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// src/pages/SortingPage.jsx
2+
import React, { useState } from "react";
3+
import LinearSearch from "./linearSearch";
4+
5+
export default function SortingPage() {
6+
const [selectedAlgo, setSelectedAlgo] = useState("");
7+
8+
const renderAlgorithm = () => {
9+
switch (selectedAlgo) {
10+
case "LinearSearch":
11+
return <LinearSearch />;
12+
13+
default:
14+
return (
15+
<div className="text-gray-400 text-lg mt-20 text-center">
16+
Select an algorithm to visualize 👆
17+
</div>
18+
);
19+
}
20+
};
21+
22+
return (
23+
<div className="flex h-screen bg-black text-white">
24+
{/* Left Sidebar */}
25+
<div className="w-64 bg-[#0f172a] p-6">
26+
<h2 className="text-xl font-bold mb-6 text-indigo-400">
27+
Searching Panel
28+
</h2>
29+
30+
<label className="block mb-2 text-sm">Algorithm:</label>
31+
<select
32+
value={selectedAlgo}
33+
onChange={(e) => setSelectedAlgo(e.target.value)}
34+
className="w-full p-2 rounded bg-[#1e293b] text-white border border-gray-600"
35+
>
36+
<option value="">Select Algorithm</option>
37+
<option value="LinearSearch">LinearSearch</option>
38+
</select>
39+
40+
<button
41+
onClick={() => setSelectedAlgo("")}
42+
className="w-full mt-4 py-2 bg-gray-600 hover:bg-gray-700 rounded"
43+
>
44+
Reset
45+
</button>
46+
47+
<a
48+
href="/"
49+
className="inline-block mt-10 text-indigo-400 hover:underline text-sm"
50+
>
51+
← Back to Home
52+
</a>
53+
</div>
54+
55+
{/* Right Visualization Area */}
56+
<div className="flex-1 flex justify-center items-center">
57+
{renderAlgorithm()}
58+
</div>
59+
</div>
60+
);
61+
}

0 commit comments

Comments
 (0)