Playground Component
Jump Search
Visualizer
Visualize Jump Search as it skips through fixed-size blocks of a sorted array, then scans inside the matching block.

Jump Search Visualizer
Status
Idle
Block Size
6
Prev
-
Step
-
Current
-
Comparisons
0
Target
-
Copy Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Jump Search Visualizer</title>
<style>
:root{--bg:#090909;--panel:#111111;--gold:#f4c430;--gold-dark:#b88700;--text:#f5f5f5;--border:#2f2f2f}
*{box-sizing:border-box}
body{margin:0;background:#090909}
.search-visualizer{min-height:100vh;padding:40px;background:radial-gradient(circle at top,#1a1505 0%,#090909 40%);color:var(--text);font-family:'Poppins',Arial,sans-serif}
.search-visualizer h2{text-align:center;font-size:3rem;color:var(--gold);margin:0 0 35px}
.controls{display:flex;justify-content:center;gap:15px;flex-wrap:wrap;margin-bottom:35px}
.controls input{width:160px;padding:14px;border-radius:12px;border:1px solid #555;background:#151515;color:var(--gold);text-align:center;font-size:16px;outline:none}
.controls input:focus{border-color:var(--gold)}
.controls button{padding:14px 22px;border:none;border-radius:12px;cursor:pointer;font-weight:600;font-size:15px;background:linear-gradient(180deg,#ffd54d,#d9a900);color:#111;transition:.25s}
.controls button:hover{transform:translateY(-2px)}
.stats{width:100%;max-width:900px;margin:auto auto 40px;display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
.stat-box{background:#151515;border:1px solid #2b2b2b;border-radius:14px;padding:18px;text-align:center}
.stat-box h4{margin:0;color:#999;font-size:.9rem}
.stat-box p{margin:8px 0 0;color:var(--gold);font-size:1.4rem;font-weight:bold}
.array{display:flex;justify-content:center;flex-wrap:wrap;gap:14px}
.cell{width:72px;height:72px;border-radius:14px;background:#171717;border:2px solid #2c2c2c;display:flex;flex-direction:column;justify-content:center;align-items:center;transition:.25s}
.cell div{font-size:1.3rem;font-weight:700}
.cell small{margin-top:5px;color:#999;font-size:.72rem}
.cell.default{background:#171717}
.cell.block{background:#241d08;border-color:#6f560f}
.cell.checking{background:#ffb000;color:black;border-color:#ffd54d;transform:translateY(-8px) scale(1.05);box-shadow:0 0 20px rgba(255,193,7,.45)}
.cell.found{background:#25c05a;color:white;border-color:#43e97b;transform:scale(1.12);box-shadow:0 0 22px rgba(37,192,90,.5)}
.cell.discarded{opacity:.28}
.cell.prev{border:2px solid #4ea8ff}
.cell.step{border:2px solid #ff6b6b}
.cell.current{background:#b26dff;border-color:#d7b3ff}
@media(max-width:768px){.search-visualizer{padding:20px}.search-visualizer h2{font-size:2rem}.stats{grid-template-columns:repeat(2,1fr)}.cell{width:58px;height:58px}.cell div{font-size:1rem}}
</style>
</head>
<body>
<div class="search-visualizer">
<h2>Jump Search Visualizer</h2>
<div class="controls">
<button id="randomizeBtn">Randomize</button>
<input id="targetInput" type="number" placeholder="Target">
<button id="searchBtn">Search</button>
<button id="speedBtn">Speed: Normal</button>
</div>
<div class="stats">
<div class="stat-box"><h4>Status</h4><p id="status">Idle</p></div>
<div class="stat-box"><h4>Block Size</h4><p id="blockSize">-</p></div>
<div class="stat-box"><h4>Prev</h4><p id="prev">-</p></div>
<div class="stat-box"><h4>Step</h4><p id="step">-</p></div>
<div class="stat-box"><h4>Current</h4><p id="current">-</p></div>
<div class="stat-box"><h4>Comparisons</h4><p id="comparisons">0</p></div>
<div class="stat-box"><h4>Target</h4><p id="targetValue">-</p></div>
</div>
<div id="array" class="array"></div>
</div>
<script>
const speedLevels=[{name:"Very Slow",delay:500},{name:"Slow",delay:200},{name:"Normal",delay:100},{name:"Fast",delay:50},{name:"Very Fast",delay:10}];
let array=[],speedIndex=2,searching=false,prev=-1,step=-1,current=-1,blockSize=Math.floor(Math.sqrt(48));
const arrayEl=document.getElementById("array"),targetInput=document.getElementById("targetInput"),speedBtn=document.getElementById("speedBtn");
function sleep(ms){return new Promise(resolve=>setTimeout(resolve,ms))}
function createSortedArray(){const used=new Set(),arr=[];while(arr.length<48){const value=Math.floor(Math.random()*100)+10;if(!used.has(value)){used.add(value);arr.push({value,state:"default"})}}return arr.sort((a,b)=>a.value-b.value)}
function setStatus(value){document.getElementById("status").textContent=value}
function setMarker(id,value){document.getElementById(id).textContent=value===-1?"-":value}
function setBlockSize(value){blockSize=value;document.getElementById("blockSize").textContent=value||"-"}
function setComparisons(value){document.getElementById("comparisons").textContent=value}
function syncTarget(){document.getElementById("targetValue").textContent=targetInput.value||"-"}
function renderArray(){
arrayEl.innerHTML="";
array.forEach((item,index)=>{
const classes=["cell"];
if(index===prev)classes.push("prev");
if(index===step)classes.push("step");
if(index===current)classes.push("current");
classes.push(item.state);
const cell=document.createElement("div");
cell.className=classes.join(" ");
cell.innerHTML=`<div>${item.value}</div><small>Index ${index}</small>`;
arrayEl.appendChild(cell);
});
}
function setPrev(value){prev=value;setMarker("prev",value);renderArray()}
function setStep(value){step=value;setMarker("step",value);renderArray()}
function setCurrent(value){current=value;setMarker("current",value);renderArray()}
function clearMarkers(){setPrev(-1);setStep(-1);setCurrent(-1)}
function setCellState(index,state){if(array[index]){array[index].state=state;renderArray()}}
function setRangeState(start,end,state){array=array.map((item,index)=>index>=start&&index<end?{...item,state}:item);renderArray()}
function resetStates(){array=array.map(item=>({...item,state:"default"}));renderArray()}
function randomize(){if(searching)return;array=createSortedArray();targetInput.value="";setBlockSize(Math.floor(Math.sqrt(array.length)));clearMarkers();setComparisons(0);setStatus("Idle");syncTarget();renderArray()}
function toggleSpeed(){speedIndex=(speedIndex+1)%speedLevels.length;speedBtn.textContent=`Speed: ${speedLevels[speedIndex].name}`}
async function jumpSearch(){
if(searching)return;
const target=Number(targetInput.value);
if(Number.isNaN(target)||targetInput.value===""||array.length===0)return;
searching=true;resetStates();clearMarkers();setComparisons(0);setStatus("Jumping...");syncTarget();
const size=Math.floor(Math.sqrt(array.length));
let blockStart=0,blockEnd=size,comps=0;
setBlockSize(size);
while(blockStart<array.length&&array[Math.min(blockEnd,array.length)-1].value<target){
const checkIndex=Math.min(blockEnd,array.length)-1;
setPrev(blockStart);setStep(checkIndex);setCurrent(checkIndex);setRangeState(blockStart,Math.min(blockEnd,array.length),"block");setCellState(checkIndex,"checking");
comps++;setComparisons(comps);
await sleep(speedLevels[speedIndex].delay);
setRangeState(blockStart,Math.min(blockEnd,array.length),"discarded");
blockStart=blockEnd;blockEnd+=size;
await sleep(speedLevels[speedIndex].delay);
}
if(blockStart>=array.length){clearMarkers();setStatus("Not Found");searching=false;return}
const scanEnd=Math.min(blockEnd,array.length);
setPrev(blockStart);setStep(scanEnd-1);setStatus("Linear scan...");setRangeState(blockStart,scanEnd,"block");
await sleep(speedLevels[speedIndex].delay);
for(let i=blockStart;i<scanEnd;i++){
setCurrent(i);setCellState(i,"checking");comps++;setComparisons(comps);
await sleep(speedLevels[speedIndex].delay);
if(array[i].value===target){setCellState(i,"found");setStatus("Found!");searching=false;return}
if(array[i].value>target){setCellState(i,"discarded");break}
setCellState(i,"discarded");
}
clearMarkers();setStatus("Not Found");searching=false;
}
document.getElementById("randomizeBtn").addEventListener("click",randomize);
document.getElementById("searchBtn").addEventListener("click",jumpSearch);
speedBtn.addEventListener("click",toggleSpeed);
targetInput.addEventListener("input",syncTarget);
randomize();
</script>
</body>
</html>
About this Component
Jump Search is a searching algorithm for sorted arrays. It moves ahead by fixed-size blocks, commonly around the square root of the array length, until it finds a block that could contain the target. It then performs a linear scan inside that smaller block. This interactive visualization shows the jump phase and the final block scan, making it easier to see how Jump Search balances skipping over many elements with checking a small range directly. Jump Search has a best-case time complexity of O(1) when the first checked element is the target, and an average and worst-case time complexity of O(sqrt n) when the jump size is chosen well. It uses O(1) extra space and requires the input data to be sorted.
Explore More Components
Discover more components from the Playground.



