制作了一个冒泡排序的演示动画,便于更好理解冒泡排序的原理及各轮排序过程。
请大家帮忙看看 有无需要改进的地方~
[HTML] 纯文本查看 复制代码 <!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>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Microsoft YaHei", sans-serif;
}
body {
background-color: #f5f7fa;
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.header {
text-align: center;
margin-bottom: 30px;
color: #2d3748;
}
.header h1 {
font-size: 28px;
margin-bottom: 10px;
color: #2b6cb0;
}
.header p {
font-size: 16px;
color: #4a5568;
}
.container {
display: flex;
flex-direction: column;
gap: 25px;
}
.visual-area {
background: white;
padding: 30px;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
min-height: 220px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.array-container {
display: flex;
align-items: flex-end;
justify-content: center;
gap: 8px;
height: 150px;
margin-bottom: 20px;
}
.bar {
width: 50px;
background-color: #4299e1;
border-radius: 4px 4px 0 0;
display: flex;
align-items: flex-end;
justify-content: center;
color: white;
font-weight: bold;
padding-bottom: 5px;
transition: all 0.3s ease;
}
.bar-comparing {
background-color: #f6ad55;
}
.bar-swapping {
background-color: #e53e3e;
}
.bar-sorted {
background-color: #38a169;
}
.step-info {
font-size: 18px;
color: #2d3748;
text-align: center;
min-height: 27px;
font-weight: 500;
}
.control-panel {
background: white;
padding: 20px;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
display: flex;
flex-wrap: wrap;
gap: 15px;
align-items: center;
justify-content: center;
}
button {
padding: 10px 20px;
border: none;
border-radius: 6px;
background-color: #2b6cb0;
color: white;
font-size: 16px;
cursor: pointer;
transition: background 0.2s;
}
button:hover {
background-color: #2c5282;
}
button:disabled {
background-color: #a0aec0;
cursor: not-allowed;
}
.speed-control {
display: flex;
align-items: center;
gap: 10px;
}
input[type="range"] {
width: 150px;
}
.code-area {
background: #2d3748;
color: #e2e8f0;
padding: 25px;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.code-area h3 {
color: #f6ad55;
margin-bottom: 15px;
font-size: 20px;
}
pre {
font-size: 15px;
line-height: 1.6;
overflow-x: auto;
}
.code-highlight {
background-color: #4a5568;
padding: 2px 4px;
border-radius: 3px;
}
.teach-info {
background: #fff3bf;
padding: 15px;
border-radius: 8px;
border-left: 4px solid #d69e2e;
color: #744210;
}
</style>
</head>
<body>
<div class="header">
<h1>冒泡排序算法可视化教学</h1>
<p>通过动态演示理解冒泡排序核心原理:相邻元素比较、交换,大数下沉/小数上浮</p>
</div>
<div class="container">
<div class="visual-area">
<div class="array-container" id="arrayContainer"></div>
<div class="step-info" id="stepInfo">准备就绪,点击开始演示</div>
</div>
<div class="control-panel">
<button id="startBtn">开始排序</button>
<button id="pauseBtn" disabled>暂停</button>
<button id="resetBtn">重置数组</button>
<button id="stepBtn">单步执行</button>
<div class="speed-control">
<span>演示速度:</span>
<input type="range" id="speedSlider" min="100" max="1000" value="500" step="100">
<span id="speedText">0.5秒</span>
</div>
</div>
<div class="teach-info">
<strong>📚 课堂知识点:</strong>
<br>1. 冒泡排序每轮循环找到当前最大元素,放到末尾
<br>2. 相邻两个数比较,逆序则交换,顺序则不变
<br>3. 蓝色=未处理,橙色=比较中,红色=交换中,绿色=已排序
</div>
<div class="code-area">
<h3>冒泡排序核心代码(JavaScript)</h3>
<pre id="codeDisplay">
function bubbleSort(arr) {
<span id="code1">let len = arr.length;</span>
<span id="code2">for(let i = 0; i < len - 1; i++) {</span>
<span id="code3"> for(let j = 0; j < len - 1 - i; j++) {</span>
<span id="code4"> if(arr[j] > arr[j+1]) {</span>
<span id="code5"> // 交换元素</span>
<span id="code6"> let temp = arr[j];</span>
<span id="code7"> arr[j] = arr[j+1];</span>
<span id="code8"> arr[j+1] = temp;</span>
<span id="code9"> }</span>
<span id="code10"> }</span>
<span id="code11">}</span>
<span id="code12">return arr;</span>
}
</pre>
</div>
</div>
<script>
let originalArray = [8, 3, 5, 4, 7, 2, 6, 1];
let currentArray = [...originalArray];
let isRunning = false;
let isPaused = false;
let speed = 500;
const arrayContainer = document.getElementById('arrayContainer');
const stepInfo = document.getElementById('stepInfo');
const startBtn = document.getElementById('startBtn');
const pauseBtn = document.getElementById('pauseBtn');
const resetBtn = document.getElementById('resetBtn');
const stepBtn = document.getElementById('stepBtn');
const speedSlider = document.getElementById('speedSlider');
const speedText = document.getElementById('speedText');
function renderArray() {
arrayContainer.innerHTML = '';
currentArray.forEach((num, index) => {
const bar = document.createElement('div');
bar.className = 'bar';
bar.style.height = `${num * 15}px`;
bar.textContent = num;
arrayContainer.appendChild(bar);
});
}
function clearCodeHighlight() {
for(let i=1; i<=12; i++) {
document.getElementById(`code${i}`).classList.remove('code-highlight');
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function bubbleSortVisual() {
if(isRunning) return;
isRunning = true;
isPaused = false;
startBtn.disabled = true;
pauseBtn.disabled = false;
stepBtn.disabled = true;
let arr = [...currentArray];
const len = arr.length;
clearCodeHighlight();
document.getElementById('code1').classList.add('code-highlight');
stepInfo.textContent = `初始化:数组长度 = ${len}`;
await sleep(speed);
for(let i = 0; i < len - 1; i++) {
clearCodeHighlight();
document.getElementById('code2').classList.add('code-highlight');
stepInfo.textContent = `第 ${i+1} 轮排序:寻找第 ${len-i} 大的数`;
await sleep(speed);
for(let j = 0; j < len - 1 - i; j++) {
while(isPaused) await sleep(50);
if(!isRunning) return;
clearCodeHighlight();
document.getElementById('code3').classList.add('code-highlight');
const bars = document.querySelectorAll('.bar');
bars[j].classList.add('bar-comparing');
bars[j+1].classList.add('bar-comparing');
stepInfo.textContent = `比较:${arr[j]} 和 ${arr[j+1]}`;
document.getElementById('code4').classList.add('code-highlight');
await sleep(speed);
if(arr[j] > arr[j+1]) {
bars[j].classList.replace('bar-comparing', 'bar-swapping');
bars[j+1].classList.replace('bar-comparing', 'bar-swapping');
stepInfo.textContent = `交换:${arr[j]} > ${arr[j+1]},执行交换`;
document.getElementById('code6').classList.add('code-highlight');
await sleep(speed/2);
document.getElementById('code7').classList.add('code-highlight');
await sleep(speed/2);
document.getElementById('code8').classList.add('code-highlight');
let temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
currentArray = [...arr];
renderArray();
await sleep(speed);
}
bars[j].classList.remove('bar-comparing', 'bar-swapping');
bars[j+1].classList.remove('bar-comparing', 'bar-swapping');
}
const bars = document.querySelectorAll('.bar');
bars[len - 1 - i].classList.add('bar-sorted');
stepInfo.textContent = `第 ${i+1} 轮完成:${arr[len-1-i]} 已到达正确位置`;
await sleep(speed);
}
clearCodeHighlight();
document.getElementById('code12').classList.add('code-highlight');
const allBars = document.querySelectorAll('.bar');
allBars.forEach(bar => bar.classList.add('bar-sorted'));
stepInfo.textContent = '✅ 排序完成!冒泡排序时间复杂度:O(n²)';
isRunning = false;
startBtn.disabled = false;
pauseBtn.disabled = true;
stepBtn.disabled = false;
}
startBtn.addEventListener('click', bubbleSortVisual);
pauseBtn.addEventListener('click', () => {
if(isRunning){
isPaused = !isPaused;
pauseBtn.textContent = isPaused ? '继续' : '暂停';
}
});
resetBtn.addEventListener('click', () => {
isRunning = false;
isPaused = false;
currentArray = [...originalArray];
renderArray();
clearCodeHighlight();
stepInfo.textContent = '已重置数组,准备就绪';
startBtn.disabled = false;
pauseBtn.disabled = true;
stepBtn.disabled = false;
pauseBtn.textContent = '暂停';
});
stepBtn.addEventListener('click', async () => {
if(!isRunning){
await bubbleSortVisual();
}
});
speedSlider.addEventListener('input', () => {
speed = parseInt(speedSlider.value);
speedText.textContent = (speed/1000).toFixed(1) + '秒';
});
window.onload = renderArray;
</script>
</body>
</html>
|