
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>链表操作教学工具</title><style>* {box-sizing: border-box;margin: 0;padding: 0;font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;}body {background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);color: #333;min-height: 100vh;padding: 20px;}.container {max-width: 1400px;margin: 0 auto;background-color: rgba(255, 255, 255, 0.95);border-radius: 15px;box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);padding: 30px;overflow: hidden;}header {text-align: center;margin-bottom: 30px;}h1 {color: #2c3e50;margin-bottom: 10px;font-size: 2.5rem;}.subtitle {color: #7f8c8d;font-size: 1.2rem;}.content {display: flex;flex-wrap: wrap;gap: 30px;}.visualization {flex: 1;min-width: 300px;background-color: #f8f9fa;border-radius: 10px;padding: 20px;box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);}.controls {flex: 1;min-width: 300px;display: flex;flex-direction: column;gap: 20px;}.panel {background-color: #fff;border-radius: 10px;padding: 20px;box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);}h2 {color: #3498db;margin-bottom: 15px;font-size: 1.5rem;border-bottom: 2px solid #eee;padding-bottom: 10px;}.input-group {display: flex;flex-wrap: wrap;gap: 10px;margin-bottom: 15px;}input, button, select {padding: 10px 15px;border-radius: 5px;border: 1px solid #ddd;font-size: 1rem;}input, select {flex: 1;min-width: 150px;}button {background-color: #3498db;color: white;border: none;cursor: pointer;transition: background-color 0.3s;}button:hover {background-color: #2980b9;}.linked-list {display: flex;flex-wrap: wrap;justify-content: center;align-items: center;gap: 10px;margin-top: 20px;min-height: 150px;}.node {display: flex;align-items: center;background-color: #3498db;color: white;border-radius: 8px;padding: 10px 15px;position: relative;transition: all 0.3s ease;box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1);}.node-value {font-weight: bold;font-size: 1.2rem;}.node-pointer {margin-left: 10px;font-size: 1.5rem;}.node.highlight {background-color: #e74c3c;transform: scale(1.1);}.node.kth-highlight {background-color: #2ecc71;transform: scale(1.1);}.code-section {margin-top: 30px;}.code-container {background-color: #2d3a4b;color: #f8f8f2;border-radius: 8px;padding: 20px;overflow-x: auto;font-family: 'Courier New', monospace;margin-top: 15px;box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);}.code-header {display: flex;justify-content: space-between;align-items: center;margin-bottom: 15px;}.code-title {font-size: 1.2rem;color: #3498db;font-weight: bold;}.code-tabs {display: flex;gap: 10px;}.code-tab {padding: 5px 10px;background-color: #34495e;border-radius: 5px;cursor: pointer;transition: background-color 0.3s;}.code-tab.active {background-color: #3498db;}.code-line {margin-bottom: 8px;line-height: 1.5;}.code-comment {color: #6272a4;}.code-keyword {color: #ff79c6;}.code-function {color: #50fa7b;}.code-type {color: #8be9fd;}.code-var {color: #f1fa8c;}.code-number {color: #bd93f9;}.explanation {margin-top: 20px;padding: 15px;background-color: #f1f8ff;border-radius: 8px;border-left: 4px solid #3498db;}.explanation h3 {color: #3498db;margin-bottom: 10px;}.explanation p {line-height: 1.6;}.algorithm {margin-top: 20px;background-color: #f9f9f9;padding: 15px;border-radius: 8px;border: 1px solid #eee;}.algorithm h3 {color: #2c3e50;margin-bottom: 10px;}.algorithm p {margin-bottom: 10px;line-height: 1.5;}.status {margin-top: 15px;padding: 10px;border-radius: 5px;text-align: center;font-weight: bold;}.status.success {background-color: #d4edda;color: #155724;border: 1px solid #c3e6cb;}.status.error {background-color: #f8d7da;color: #721c24;border: 1px solid #f5c6cb;}.status.info {background-color: #d1ecf1;color: #0c5460;border: 1px solid #bee5eb;}@media (max-width: 768px) {.content {flex-direction: column;}.visualization, .controls {width: 100%;}}</style>
</head>
<body><div class="container"><header><h1>链表操作教学工具</h1><p class="subtitle">可视化学习链表的增删改查及查找倒数第k个元素</p></header><div class="content"><div class="visualization"><h2>链表可视化</h2><div class="linked-list" id="linkedList"></div><div class="explanation"><h3>链表简介</h3><p>链表是一种线性数据结构,其中的元素(节点)通过指针连接。每个节点包含数据和指向下一个节点的指针。与数组不同,链表在内存中不是连续存储的。</p></div><div class="algorithm"><h3>查找倒数第k个元素的算法</h3><p>1. 使用两个指针:快指针和慢指针</p><p>2. 快指针先移动k步</p><p>3. 然后快慢指针同时移动,直到快指针到达链表末尾</p><p>4. 此时慢指针指向的就是倒数第k个元素</p></div><div class="code-section"><h2>C语言代码</h2><div class="code-container"><div class="code-header"><div class="code-title">链表操作C语言实现</div><div class="code-tabs"><div class="code-tab active" data-tab="struct">结构定义</div><div class="code-tab" data-tab="add">添加节点</div><div class="code-tab" data-tab="delete">删除节点</div><div class="code-tab" data-tab="findk">查找倒数第k个</div></div></div><div id="codeContent"></div></div></div></div><div class="controls"><div class="panel"><h2>链表操作</h2><div class="input-group"><input type="number" id="nodeValue" placeholder="输入节点值"><button id="addNode">添加节点</button></div><div class="input-group"><input type="number" id="deleteIndex" placeholder="输入要删除的节点位置"><button id="deleteNode">删除节点</button></div><div class="input-group"><input type="number" id="updateIndex" placeholder="输入要更新的节点位置"><input type="number" id="updateValue" placeholder="输入新值"><button id="updateNode">更新节点</button></div><div class="input-group"><input type="number" id="searchValue" placeholder="输入要查找的值"><button id="searchNode">查找节点</button></div><div class="input-group"><input type="number" id="kValue" placeholder="输入k值"><button id="findKth">查找倒数第k个节点</button></div><button id="resetList" style="background-color: #e74c3c;">重置链表</button><div id="statusMessage" class="status"></div></div><div class="panel"><h2>操作说明</h2><div class="explanation"><h3>添加节点</h3><p>在输入框中输入节点值,点击"添加节点"按钮,新节点将被添加到链表末尾。</p><h3>删除节点</h3><p>输入要删除的节点位置(从1开始计数),点击"删除节点"按钮。</p><h3>更新节点</h3><p>输入要更新的节点位置和新值,点击"更新节点"按钮。</p><h3>查找节点</h3><p>输入要查找的值,点击"查找节点"按钮,匹配的节点将高亮显示。</p><h3>查找倒数第k个节点</h3><p>输入k值,点击"查找倒数第k个节点"按钮,将显示倒数第k个节点。</p></div></div></div></div></div><script>class ListNode {constructor(value) {this.value = value;this.next = null;}}class LinkedList {constructor() {this.head = null;this.size = 0;}add(value) {const newNode = new ListNode(value);if (!this.head) {this.head = newNode;} else {let current = this.head;while (current.next) {current = current.next;}current.next = newNode;}this.size++;return true;}deleteAt(position) {if (position < 1 || position > this.size) {return false;}if (position === 1) {this.head = this.head.next;} else {let current = this.head;let previous = null;let index = 1;while (index < position) {previous = current;current = current.next;index++;}previous.next = current.next;}this.size--;return true;}updateAt(position, newValue) {if (position < 1 || position > this.size) {return false;}let current = this.head;let index = 1;while (index < position) {current = current.next;index++;}current.value = newValue;return true;}search(value) {let current = this.head;let index = 1;let positions = [];while (current) {if (current.value === value) {positions.push(index);}current = current.next;index++;}return positions;}findKthFromEnd(k) {if (k < 1 || k > this.size) {return null;}let fast = this.head;let slow = this.head;for (let i = 0; i < k; i++) {fast = fast.next;}while (fast) {fast = fast.next;slow = slow.next;}return slow;}getValues() {const values = [];let current = this.head;while (current) {values.push(current.value);current = current.next;}return values;}}const cCodeSnippets = {struct: `
<span class="code-comment">// 链表节点结构定义</span>
<span class="code-keyword">typedef struct</span> <span class="code-type">ListNode</span> {<span class="code-type">int</span> <span class="code-var">val</span>;<span class="code-keyword">struct</span> <span class="code-type">ListNode</span> *<span class="code-var">next</span>;
} <span class="code-type">ListNode</span>;<span class="code-comment">// 创建新节点</span>
<span class="code-type">ListNode</span>* <span class="code-function">createNode</span>(<span class="code-type">int</span> <span class="code-var">val</span>) {<span class="code-type">ListNode</span>* <span class="code-var">newNode</span> = (<span class="code-type">ListNode</span>*)<span class="code-function">malloc</span>(<span class="code-keyword">sizeof</span>(<span class="code-type">ListNode</span>));<span class="code-var">newNode</span>-><span class="code-var">val</span> = <span class="code-var">val</span>;<span class="code-var">newNode</span>-><span class="code-var">next</span> = <span class="code-keyword">NULL</span>;<span class="code-keyword">return</span> <span class="code-var">newNode</span>;
}`,add: `
<span class="code-comment">// 在链表末尾添加节点</span>
<span class="code-type">void</span> <span class="code-function">addNode</span>(<span class="code-type">ListNode</span>** <span class="code-var">head</span>, <span class="code-type">int</span> <span class="code-var">val</span>) {<span class="code-type">ListNode</span>* <span class="code-var">newNode</span> = <span class="code-function">createNode</span>(<span class="code-var">val</span>);<span class="code-keyword">if</span> (*<span class="code-var">head</span> == <span class="code-keyword">NULL</span>) {*<span class="code-var">head</span> = <span class="code-var">newNode</span>;<span class="code-keyword">return</span>;}<span class="code-type">ListNode</span>* <span class="code-var">current</span> = *<span class="code-var">head</span>;<span class="code-keyword">while</span> (<span class="code-var">current</span>-><span class="code-var">next</span> != <span class="code-keyword">NULL</span>) {<span class="code-var">current</span> = <span class="code-var">current</span>-><span class="code-var">next</span>;}<span class="code-var">current</span>-><span class="code-var">next</span> = <span class="code-var">newNode</span>;
}`,delete: `
<span class="code-comment">// 删除指定位置的节点</span>
<span class="code-type">int</span> <span class="code-function">deleteNode</span>(<span class="code-type">ListNode</span>** <span class="code-var">head</span>, <span class="code-type">int</span> <span class="code-var">position</span>) {<span class="code-keyword">if</span> (*<span class="code-var">head</span> == <span class="code-keyword">NULL</span> || <span class="code-var">position</span> < <span class="code-number">1</span>) {<span class="code-keyword">return</span> <span class="code-number">0</span>; <span class="code-comment">// 删除失败</span>}<span class="code-keyword">if</span> (<span class="code-var">position</span> == <span class="code-number">1</span>) {<span class="code-type">ListNode</span>* <span class="code-var">temp</span> = *<span class="code-var">head</span>;*<span class="code-var">head</span> = (*<span class="code-var">head</span>)-><span class="code-var">next</span>;<span class="code-function">free</span>(<span class="code-var">temp</span>);<span class="code-keyword">return</span> <span class="code-number">1</span>; <span class="code-comment">// 删除成功</span>}<span class="code-type">ListNode</span>* <span class="code-var">current</span> = *<span class="code-var">head</span>;<span class="code-type">ListNode</span>* <span class="code-var">prev</span> = <span class="code-keyword">NULL</span>;<span class="code-type">int</span> <span class="code-var">count</span> = <span class="code-number">1</span>;<span class="code-keyword">while</span> (<span class="code-var">current</span> != <span class="code-keyword">NULL</span> && <span class="code-var">count</span> < <span class="code-var">position</span>) {<span class="code-var">prev</span> = <span class="code-var">current</span>;<span class="code-var">current</span> = <span class="code-var">current</span>-><span class="code-var">next</span>;<span class="code-var">count</span>++;}<span class="code-keyword">if</span> (<span class="code-var">current</span> == <span class="code-keyword">NULL</span>) {<span class="code-keyword">return</span> <span class="code-number">0</span>; <span class="code-comment">// 位置超出链表长度</span>}<span class="code-var">prev</span>-><span class="code-var">next</span> = <span class="code-var">current</span>-><span class="code-var">next</span>;<span class="code-function">free</span>(<span class="code-var">current</span>);<span class="code-keyword">return</span> <span class="code-number">1</span>; <span class="code-comment">// 删除成功</span>
}`,findk: `
<span class="code-comment">// 查找倒数第k个节点</span>
<span class="code-type">ListNode</span>* <span class="code-function">findKthFromEnd</span>(<span class="code-type">ListNode</span>* <span class="code-var">head</span>, <span class="code-type">int</span> <span class="code-var">k</span>) {<span class="code-keyword">if</span> (<span class="code-var">head</span> == <span class="code-keyword">NULL</span> || <span class="code-var">k</span> <= <span class="code-number">0</span>) {<span class="code-keyword">return</span> <span class="code-keyword">NULL</span>;}<span class="code-type">ListNode</span>* <span class="code-var">fast</span> = <span class="code-var">head</span>;<span class="code-type">ListNode</span>* <span class="code-var">slow</span> = <span class="code-var">head</span>;<span class="code-comment">// 快指针先移动k步</span><span class="code-keyword">for</span> (<span class="code-type">int</span> <span class="code-var">i</span> = <span class="code-number">0</span>; <span class="code-var">i</span> < <span class="code-var">k</span>; <span class="code-var">i</span>++) {<span class="code-keyword">if</span> (<span class="code-var">fast</span> == <span class="code-keyword">NULL</span>) {<span class="code-keyword">return</span> <span class="code-keyword">NULL</span>; <span class="code-comment">// k大于链表长度</span>}<span class="code-var">fast</span> = <span class="code-var">fast</span>-><span class="code-var">next</span>;}<span class="code-comment">// 快慢指针同时移动,直到快指针到达末尾</span><span class="code-keyword">while</span> (<span class="code-var">fast</span> != <span class="code-keyword">NULL</span>) {<span class="code-var">fast</span> = <span class="code-var">fast</span>-><span class="code-var">next</span>;<span class="code-var">slow</span> = <span class="code-var">slow</span>-><span class="code-var">next</span>;}<span class="code-keyword">return</span> <span class="code-var">slow</span>;
}`};const linkedList = new LinkedList();const linkedListElement = document.getElementById('linkedList');const statusMessage = document.getElementById('statusMessage');const codeContent = document.getElementById('codeContent');function renderLinkedList(highlightIndex = null, kthHighlight = null) {linkedListElement.innerHTML = '';if (linkedList.size === 0) {linkedListElement.innerHTML = '<p style="text-align: center; color: #7f8c8d;">链表为空,请添加节点</p>';return;}let current = linkedList.head;let index = 1;while (current) {const nodeElement = document.createElement('div');nodeElement.className = 'node';if (highlightIndex && highlightIndex.includes(index)) {nodeElement.classList.add('highlight');}if (kthHighlight && kthHighlight === index) {nodeElement.classList.add('kth-highlight');}nodeElement.innerHTML = `<div class="node-value">${current.value}</div>${current.next ? '<div class="node-pointer">→</div>' : ''}`;linkedListElement.appendChild(nodeElement);current = current.next;index++;}}function renderCode(tab) {codeContent.innerHTML = cCodeSnippets[tab];document.querySelectorAll('.code-tab').forEach(tabElement => {if (tabElement.getAttribute('data-tab') === tab) {tabElement.classList.add('active');} else {tabElement.classList.remove('active');}});}function showStatus(message, type = 'info') {statusMessage.textContent = message;statusMessage.className = `status ${type}`;setTimeout(() => {statusMessage.textContent = '';statusMessage.className = 'status';}, 3000);}document.getElementById('addNode').addEventListener('click', () => {const valueInput = document.getElementById('nodeValue');const value = parseInt(valueInput.value);if (isNaN(value)) {showStatus('请输入有效的节点值', 'error');return;}linkedList.add(value);renderLinkedList();valueInput.value = '';showStatus(`成功添加节点: ${value}`, 'success');});document.getElementById('deleteNode').addEventListener('click', () => {const indexInput = document.getElementById('deleteIndex');const position = parseInt(indexInput.value);if (isNaN(position) || position < 1) {showStatus('请输入有效的节点位置', 'error');return;}if (linkedList.deleteAt(position)) {renderLinkedList();indexInput.value = '';showStatus(`成功删除位置 ${position} 的节点`, 'success');} else {showStatus(`位置 ${position} 无效,无法删除节点`, 'error');}});document.getElementById('updateNode').addEventListener('click', () => {const indexInput = document.getElementById('updateIndex');const valueInput = document.getElementById('updateValue');const position = parseInt(indexInput.value);const newValue = parseInt(valueInput.value);if (isNaN(position) || position < 1 || isNaN(newValue)) {showStatus('请输入有效的节点位置和新值', 'error');return;}if (linkedList.updateAt(position, newValue)) {renderLinkedList([position]);indexInput.value = '';valueInput.value = '';showStatus(`成功更新位置 ${position} 的节点值为 ${newValue}`, 'success');} else {showStatus(`位置 ${position} 无效,无法更新节点`, 'error');}});document.getElementById('searchNode').addEventListener('click', () => {const valueInput = document.getElementById('searchValue');const value = parseInt(valueInput.value);if (isNaN(value)) {showStatus('请输入有效的查找值', 'error');return;}const positions = linkedList.search(value);if (positions.length > 0) {renderLinkedList(positions);valueInput.value = '';showStatus(`找到值为 ${value} 的节点,位置: ${positions.join(', ')}`, 'success');} else {showStatus(`未找到值为 ${value} 的节点`, 'error');}});document.getElementById('findKth').addEventListener('click', () => {const kInput = document.getElementById('kValue');const k = parseInt(kInput.value);if (isNaN(k) || k < 1) {showStatus('请输入有效的k值', 'error');return;}const kthNode = linkedList.findKthFromEnd(k);if (kthNode) {let position = 1;let current = linkedList.head;while (current !== kthNode) {current = current.next;position++;}renderLinkedList(null, position);kInput.value = '';showStatus(`倒数第 ${k} 个节点的值为: ${kthNode.value}`, 'success');} else {showStatus(`k值 ${k} 无效,链表长度: ${linkedList.size}`, 'error');}});document.getElementById('resetList').addEventListener('click', () => {linkedList.head = null;linkedList.size = 0;renderLinkedList();showStatus('链表已重置', 'info');});document.querySelectorAll('.code-tab').forEach(tab => {tab.addEventListener('click', () => {const tabName = tab.getAttribute('data-tab');renderCode(tabName);});});renderLinkedList();renderCode('struct');</script>
</body>
</html>