Playground Component

Reverse Linked
List Visualizer

An interactive linked list visualization that shows how a list is reversed by moving prev, curr, and next pointers step by step.

Reverse Linked List Visualizer

Reverse a Linked List Visualizer

Prev

NULL

Curr

10

Next

20

Step

0 / 10

Action

-

Status

Ready

Linked List

Head
Curr
10
Next
30
40
50
NULL

Algorithm

1while (curr != null) {
2 next = curr.next;
3 curr.next = prev;
4 prev = curr;
5 curr = next;
6}

Copy Code

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
<title>Reverse Linked List Visualizer</title>
<style>
:root{--bg:#090909;--panel:#111;--gold:#f4c430;--gold-dark:#b88700;--text:#f5f5f5;--border:#2f2f2f}*{box-sizing:border-box}body{margin:0}.reverse-ll{min-height:100vh;padding:40px;background:radial-gradient(circle at top,#1a1505 0%,#090909 40%);color:var(--text);font-family:Poppins,Arial,sans-serif}.reverse-ll h2{text-align:center;font-size:3rem;color:var(--gold);margin:0 0 35px}.reverse-ll-controls{display:flex;justify-content:center;gap:15px;flex-wrap:wrap;margin-bottom:35px}.reverse-ll-button{padding:14px 22px;border:0;border-radius:12px;cursor:pointer;font-weight:600;font-size:15px;background:linear-gradient(180deg,#ffd54d,#d9a900);color:#111;display:inline-flex;align-items:center;gap:10px;transition:.25s}.reverse-ll-button:hover{transform:translateY(-2px)}.reverse-ll-button:disabled{cursor:not-allowed;opacity:.55;transform:none}.reverse-ll-stats{width:100%;max-width:900px;margin:auto;margin-bottom:40px;display:grid;grid-template-columns:1fr 1fr 1fr 1fr 2fr 1fr;gap:18px}.reverse-ll-stat-box{background:#151515;border:1px solid #2b2b2b;border-radius:14px;padding:18px;text-align:center}.reverse-ll-stat-box h4{margin:0;color:#999;font-size:.9rem}.reverse-ll-stat-box p{margin:8px 0 0;color:var(--gold);font-size:1.4rem;font-weight:bold}.reverse-ll-code,.reverse-ll-stage{width:100%;max-width:1400px;margin:0 auto 30px;padding:24px 26px 20px;border:1px solid var(--border);border-radius:18px;background:#111}.reverse-ll-code h3,.reverse-ll-stage h3{margin:0 0 16px;text-align:center;color:var(--gold);font-size:1.6rem}.reverse-ll-code-block{margin:0;font-family:"Fira Code","Courier New",monospace;font-size:1rem;line-height:1.9;background:#0c0c0c;border:1px solid #222;border-radius:12px;padding:16px 10px}.reverse-ll-code-line{display:flex;align-items:center;gap:16px;padding:2px 14px;border-left:3px solid transparent;border-radius:6px;color:#8a8a8a;white-space:pre;transition:.3s}.reverse-ll-code-linenum{color:#4a4a4a;font-size:.85rem;min-width:16px;text-align:right}.reverse-ll-code-line.active{color:var(--gold);background:rgba(244,196,48,.1);border-left-color:var(--gold);transform:translateX(4px);animation:glow 1.1s ease-in-out infinite}.reverse-ll-code-line.active .reverse-ll-code-linenum{color:var(--gold)}@keyframes glow{50%{box-shadow:0 0 18px rgba(244,196,48,.32) inset,0 0 20px rgba(244,196,48,.28)}}.reverse-ll-stage{padding:28px 30px 34px}.reverse-ll-stage h3{margin-bottom:28px}.reverse-ll-chain{--curr-move-distance:170px;display:flex;align-items:center;justify-content:center;gap:10px;min-height:132px;overflow-x:auto;padding:8px 4px 22px}.reverse-ll-label,.reverse-ll-null{color:var(--gold);font-weight:700;white-space:nowrap}.reverse-ll-node-wrap{display:flex;flex-direction:column;align-items:center;gap:8px;min-width:82px}.reverse-ll-pointer-stack{width:100%;height:44px;display:flex;align-items:flex-end;justify-content:center;flex-wrap:wrap;gap:4px}.reverse-ll-pointer-badge{position:relative;z-index:2;min-width:34px;min-height:18px;padding:2px 5px;border:1px solid #343434;border-radius:5px;background:#111;color:#999;display:inline-flex;align-items:center;justify-content:center;font-size:.68rem;font-weight:700;text-transform:uppercase;transition:.45s}.prev-pointer{border-color:#54a8ff;color:#91c8ff}.prev-pointer.moving,.curr-pointer.moving,.next-pointer.moving{transform:translateX(var(--curr-move-distance)) translateY(-5px)}.curr-pointer{color:var(--gold);border-color:var(--gold);box-shadow:0 0 14px rgba(244,196,48,.3)}.next-pointer{border-color:#ff7b7b;color:#ffaaa8}.reverse-ll-node{width:72px;height:72px;border-radius:14px;background:#171717;border:2px solid #2c2c2c;color:var(--text);display:flex;align-items:center;justify-content:center;font-size:1.3rem;font-weight:700;transition:.25s}.reverse-ll-node.curr{background:#ffb000;color:#000;border-color:#ffd54d;transform:translateY(-8px) scale(1.05);box-shadow:0 0 20px rgba(255,193,7,.45)}.reverse-ll-node.prev{border-color:#4ea8ff}.reverse-ll-node.next{border-color:#ff6b6b}.reverse-ll-node.moving{transform:translateY(-12px) scale(1.05)}.reverse-ll-node.reversed,.reverse-ll-node.done{background:#25c05a;color:#fff;border-color:#43e97b;box-shadow:0 0 22px rgba(37,192,90,.35)}.reverse-ll-arrow{position:relative;width:78px;height:22px;flex:0 0 78px;transition:.45s}.reverse-ll-arrow:before{content:"";position:absolute;left:0;right:13px;top:50%;height:4px;border-radius:999px;background:var(--gold);transform:translateY(-50%)}.reverse-ll-arrow:after{content:"";position:absolute;right:0;top:50%;border-top:11px solid transparent;border-bottom:11px solid transparent;border-left:17px solid var(--gold);transform:translateY(-50%)}.reverse-ll-arrow.backward{transform:rotate(180deg)}.reverse-ll-arrow.cut{opacity:.22}.reverse-ll-dot{width:20px;height:20px;border-radius:50%;background:var(--gold-dark);box-shadow:0 0 18px rgba(244,196,48,.3)}@media(max-width:768px){.reverse-ll{padding:20px}.reverse-ll h2{font-size:2rem}.reverse-ll-stats{grid-template-columns:repeat(2,1fr)}.reverse-ll-code,.reverse-ll-stage{padding:18px 14px 14px}.reverse-ll-code-block{font-size:.85rem}.reverse-ll-chain{--curr-move-distance:130px;justify-content:flex-start}.reverse-ll-node{width:58px;height:58px;font-size:1rem}.reverse-ll-node-wrap{min-width:58px}.reverse-ll-arrow{width:56px;flex-basis:56px}}
</style>
</head>
<body><main class="reverse-ll"><h2>Reverse a Linked List Visualizer</h2><div class="reverse-ll-controls"><button id="reverseBtn" class="reverse-ll-button">&#8635; Reverse</button><button id="pauseBtn" class="reverse-ll-button">&#10073;&#10073; Pause</button><button id="speedBtn" class="reverse-ll-button"></button><button id="resetBtn" class="reverse-ll-button">Reset</button></div><div id="stats" class="reverse-ll-stats"></div><section class="reverse-ll-stage"><h3>Linked List</h3><div id="chain" class="reverse-ll-chain"></div></section><section class="reverse-ll-code"><h3>Algorithm</h3><pre id="code" class="reverse-ll-code-block"></pre></section></main>
<script>
const initialNodes=[10,20,30,40,50],speedLevels=[["Very Slow",900],["Slow",650],["Normal",450],["Fast",260],["Very Fast",120]],codeLines=["while (curr != null) {","    next = curr.next;","    curr.next = prev;","    prev = curr;","    curr = next;","}"],lineMap={"Store next":1,"Detach arrow":2,"Point to NULL":2,"Reverse arrow":2,"Move prev":3,"Move curr":4,"Move next":1};
let nodes,links,speedIndex=2,prevIndex=null,currIndex=0,nextIndex=1,movingIndex=null,movingPointer=null,step=0,action="-",status="Ready",running=false,paused=false;
const sleep=ms=>new Promise(async r=>setTimeout(async()=>{while(paused)await new Promise(x=>setTimeout(x,120));r()},ms));const pointerValue=i=>i===null?"NULL":initialNodes[i];
function reset(force=false){if(running&&!force)return;paused=false;nodes=initialNodes.map(value=>({value,state:"default"}));links=Array(initialNodes.length-1).fill("forward");prevIndex=null;currIndex=0;nextIndex=1;movingIndex=null;movingPointer=null;step=0;action="-";status="Ready";running=false;render()}
function badges(i){let b=[];if(i===prevIndex)b.push(["Prev","prev-pointer "+(movingPointer==="prev"?"moving":"")]);if(i===currIndex)b.push(["Curr","curr-pointer "+(movingPointer==="curr"?"moving":"")]);if(i===nextIndex)b.push(["Next","next-pointer "+(movingPointer==="next"?"moving":"")]);return b.map(x=>`<span class="reverse-ll-pointer-badge ${x[1]}">${x[0]}</span>`).join("")}
function nodeClass(i){let c=["reverse-ll-node",nodes[i].state];if(i===prevIndex)c.push("prev");if(i===currIndex)c.push("curr");if(i===nextIndex)c.push("next");if(i===movingIndex)c.push("moving");return c.join(" ")}
function render(){document.getElementById("reverseBtn").disabled=running||status==="Completed";document.getElementById("pauseBtn").disabled=!running;document.getElementById("pauseBtn").innerHTML=paused?"&#9654; Play":"&#10073;&#10073; Pause";document.getElementById("speedBtn").textContent="Speed: "+speedLevels[speedIndex][0];document.getElementById("stats").innerHTML=["Prev","Curr","Next","Step","Action","Status"].map((h,i)=>{let v=[pointerValue(prevIndex),pointerValue(currIndex),pointerValue(nextIndex),step+" / 10",action,status][i];return`<div class="reverse-ll-stat-box"><h4>${h}</h4><p>${v}</p></div>`}).join("");let html=`<span class="reverse-ll-label">Head</span><span class="reverse-ll-arrow"></span>`;initialNodes.forEach((_,i)=>{html+=`<div class="reverse-ll-node-wrap"><div class="reverse-ll-pointer-stack">${badges(i)}</div><div class="${nodeClass(i)}">${nodes[i].value}</div></div>`;if(i<initialNodes.length-1)html+=`<span class="reverse-ll-arrow ${links[i]}"></span>`});html+=`<span class="reverse-ll-arrow"></span><span class="reverse-ll-dot"></span><span class="reverse-ll-null">NULL</span>`;chain.innerHTML=html;let active=running||status==="Completed"?lineMap[action]:null;code.innerHTML=codeLines.map((l,i)=>`<div class="reverse-ll-code-line ${active===i?"active":""}"><span class="reverse-ll-code-linenum">${i+1}</span><span>${l}</span></div>`).join("")}
async function reverseList(){if(running)return;reset(true);running=true;status="Reversing";let prev=null,curr=0,next=1,currentStep=0;render();while(curr!==null){prevIndex=prev;currIndex=curr;nextIndex=next;nodes[curr].state="current";action="Store next";step=++currentStep;movingIndex=next;render();await sleep(speedLevels[speedIndex][1]);movingIndex=null;action=curr<initialNodes.length-1?"Detach arrow":"Point to NULL";if(curr<initialNodes.length-1)links[curr]="cut";render();await sleep(speedLevels[speedIndex][1]);action=prev===null?"Point to NULL":"Reverse arrow";step=++currentStep;movingIndex=curr;if(prev!==null)links[prev]="backward";nodes[curr].state="reversed";render();await sleep(speedLevels[speedIndex][1]);movingIndex=null;action="Move prev";if(prev!==null){movingPointer="prev";render();await sleep(speedLevels[speedIndex][1]);movingPointer=null}prev=curr;prevIndex=prev;render();await sleep(speedLevels[speedIndex][1]);action="Move curr";movingPointer="curr";render();await sleep(speedLevels[speedIndex][1]);curr=next;currIndex=curr;movingPointer=null;render();await sleep(speedLevels[speedIndex][1]);action=curr===null?"Head moved":"Move next";movingPointer="next";render();await sleep(speedLevels[speedIndex][1]);next=curr===null||curr===initialNodes.length-1?null:curr+1;nextIndex=next;movingPointer=null;movingIndex=next;render();await sleep(speedLevels[speedIndex][1]);movingIndex=null}await sleep(speedLevels[speedIndex][1]);links=Array(initialNodes.length-1).fill("backward");nodes=nodes.map(n=>({...n,state:"done"}));prevIndex=4;currIndex=null;nextIndex=null;movingPointer=null;action="New head is 50";status="Completed";running=false;paused=false;render()}
reverseBtn.onclick=reverseList;pauseBtn.onclick=()=>{if(!running)return;paused=!paused;status=paused?"Paused":"Reversing";render()};speedBtn.onclick=()=>{speedIndex=(speedIndex+1)%speedLevels.length;render()};resetBtn.onclick=()=>reset();reset();
</script></body></html>

About this Component

Reverse a Linked List is a fundamental linked list algorithm that changes every node pointer so the tail becomes the new head. This visualizer animates the prev, curr, and next pointers while each connection is cut and redirected. It helps learners understand why the next pointer must be stored before changing curr.next. The iterative approach runs in O(n) time and uses O(1) extra space because each node is visited once and the reversal happens in place.

Explore More Components

Discover more components from the Playground.

Share Feedback