<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>八大排序算法可视化演示</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#3B82F6',
secondary: '#10B981',
accent: '#8B5CF6',
dark: '#1F2937',
light: '#F3F4F6',
danger: '#EF4444',
warning: '#F59E0B'
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},
}
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.sort-bar {
@apply bg-primary rounded-t transition-all duration-150 ease-out;
}
.sort-bar-active {
@apply bg-accent;
}
.sort-bar-completed {
@apply bg-secondary;
}
.sort-bar-compared {
@apply bg-warning;
}
.sort-bar-min {
@apply bg-danger;
}
}
</style>
</head>
<body class="bg-gray-50 font-sans text-dark">
<!-- 顶部导航栏 -->
<header class="bg-white shadow-md fixed top-0 left-0 right-0 z-50 transition-all duration-300">
<div class="container mx-auto px-4 py-3 flex justify-between items-center">
<div class="flex items-center space-x-2">
<i class="fa fa-sort-amount-asc text-primary text-2xl"></i>
<h1 class="text-xl md:text-2xl font-bold text-dark">八大排序算法可视化</h1>
</div>
<nav class="hidden md:flex items-center space-x-6">
<a href="#algorithms" class="text-gray-600 hover:text-primary transition-colors">算法列表</a>
<a href="#comparison" class="text-gray-600 hover:text-primary transition-colors">算法比较</a>
<a href="#about" class="text-gray-600 hover:text-primary transition-colors">关于</a>
</nav>
<button class="md:hidden text-gray-600 hover:text-primary" id="mobileMenuBtn">
<i class="fa fa-bars text-xl"></i>
</button>
</div>
<!-- 移动端菜单 -->
<div id="mobileMenu" class="hidden md:hidden bg-white border-t">
<div class="container mx-auto px-4 py-2 flex flex-col space-y-3">
<a href="#algorithms" class="py-2 text-gray-600 hover:text-primary transition-colors">算法列表</a>
<a href="#comparison" class="py-2 text-gray-600 hover:text-primary transition-colors">算法比较</a>
<a href="#about" class="py-2 text-gray-600 hover:text-primary transition-colors">关于</a>
</div>
</div>
</header>
<!-- 主内容区 -->
<main class="container mx-auto px-4 pt-24 pb-16">
<!-- 介绍部分 -->
<section class="mb-12 text-center max-w-3xl mx-auto">
<h2 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold mb-4 text-dark">直观理解排序算法</h2>
<p class="text-gray-600 text-lg mb-8">通过动画演示直观了解八大经典排序算法的工作原理,包括冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序和基数排序。</p>
<div class="flex flex-wrap justify-center gap-4">
<a href="#visualization" class="bg-primary hover:bg-primary/90 text-white font-medium px-6 py-3 rounded-lg shadow-md transition-all hover:shadow-lg transform hover:-translate-y-0.5">
开始演示 <i class="fa fa-play ml-2"></i>
</a>
<a href="#algorithms" class="bg-white hover:bg-gray-50 text-primary border border-primary font-medium px-6 py-3 rounded-lg shadow-sm transition-all hover:shadow transform hover:-translate-y-0.5">
了解算法 <i class="fa fa-info-circle ml-2"></i>
</a>
</div>
</section>
<!-- 可视化区域 -->
<section id="visualization" class="bg-white rounded-xl shadow-lg p-6 md:p-8 mb-16 transform transition-all hover:shadow-xl">
<div class="mb-8">
<h3 class="text-2xl font-bold mb-6 flex items-center">
<i class="fa fa-bar-chart text-primary mr-3"></i>
排序可视化
</h3>
<!-- 控制区 -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div class="space-y-3">
<label class="block text-sm font-medium text-gray-700">选择算法</label>
<select id="algorithmSelect" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-all">
<option value="bubble">冒泡排序</option>
<option value="selection">选择排序</option>
<option value="insertion">插入排序</option>
<option value="shell">希尔排序</option>
<option value="merge">归并排序</option>
<option value="quick">快速排序</option>
<option value="heap">堆排序</option>
<option value="radix">基数排序</option>
</select>
</div>
<div class="space-y-3">
<label class="block text-sm font-medium text-gray-700">数组大小</label>
<input type="range" id="arraySize" min="5" max="100" value="30"
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-primary">
<div class="flex justify-between text-xs text-gray-500">
<span>5</span>
<span id="arraySizeValue">30</span>
<span>100</span>
</div>
</div>
<div class="space-y-3">
<label class="block text-sm font-medium text-gray-700">排序速度</label>
<input type="range" id="sortSpeed" min="10" max="1000" value="200"
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-primary">
<div class="flex justify-between text-xs text-gray-500">
<span>快</span>
<span id="sortSpeedValue">200ms</span>
<span>慢</span>
</div>
</div>
</div>
<!-- 按钮组 -->
<div class="flex flex-wrap gap-4 mb-8">
<button id="generateBtn" class="flex items-center px-5 py-2.5 bg-primary hover:bg-primary/90 text-white rounded-lg shadow transition-all">
<i class="fa fa-random mr-2"></i> 生成新数组
</button>
<button id="sortBtn" class="flex items-center px-5 py-2.5 bg-secondary hover:bg-secondary/90 text-white rounded-lg shadow transition-all">
<i class="fa fa-play mr-2"></i> 开始排序
</button>
<button id="pauseBtn" class="flex items-center px-5 py-2.5 bg-warning hover:bg-warning/90 text-white rounded-lg shadow transition-all" disabled>
<i class="fa fa-pause mr-2"></i> 暂停
</button>
<button id="resetBtn" class="flex items-center px-5 py-2.5 bg-danger hover:bg-danger/90 text-white rounded-lg shadow transition-all" disabled>
<i class="fa fa-refresh mr-2"></i> 重置
</button>
</div>
<!-- 排序状态 -->
<div id="sortStatus" class="mb-6 p-4 bg-gray-50 rounded-lg border border-gray-200">
<div class="flex items-center">
<div id="statusIcon" class="w-3 h-3 rounded-full bg-gray-400 mr-2"></div>
<span id="statusText" class="text-gray-600">就绪:请生成数组并选择排序算法</span>
</div>
<div class="mt-3 hidden" id="sortStats">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm">
<div class="flex items-center">
<i class="fa fa-exchange text-primary mr-2"></i>
<span>比较次数:<span id="comparisonCount">0</span></span>
</div>
<div class="flex items-center">
<i class="fa fa-arrows-v text-accent mr-2"></i>
<span>交换次数:<span id="swapCount">0</span></span>
</div>
<div class="flex items-center">
<i class="fa fa-clock-o text-warning mr-2"></i>
<span>耗时:<span id="timeElapsed">0</span>ms</span>
</div>
</div>
</div>
</div>
<!-- 可视化区域 -->
<div id="visualizationContainer" class="w-full h-[300px] md:h-[400px] flex items-end justify-center gap-[2px] md:gap-[4px] px-2 overflow-x-auto py-4 bg-gray-50 rounded-lg border border-gray-200">
<!-- 排序的柱子将在这里动态生成 -->
</div>
<!-- 图例 -->
<div class="flex flex-wrap justify-center gap-4 mt-6 text-sm">
<div class="flex items-center">
<div class="w-4 h-4 bg-primary rounded-sm mr-2"></div>
<span>未排序</span>
</div>
<div class="flex items-center">
<div class="w-4 h-4 bg-accent rounded-sm mr-2"></div>
<span>当前操作</span>
</div>
<div class="flex items-center">
<div class="w-4 h-4 bg-secondary rounded-sm mr-2"></div>
<span>已排序</span>
</div>
<div class="flex items-center">
<div class="w-4 h-4 bg-warning rounded-sm mr-2"></div>
<span>比较中</span>
</div>
<div class="flex items-center">
<div class="w-4 h-4 bg-danger rounded-sm mr-2"></div>
<span>最小值</span>
</div>
</div>
</div>
<!-- 代码展示 -->
<div>
<h3 class="text-xl font-bold mb-4 flex items-center">
<i class="fa fa-code text-primary mr-2"></i>
算法代码
</h3>
<div class="bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto">
<pre id="algorithmCode" class="text-sm md:text-base"><code>// 冒泡排序算法
function bubbleSort(arr) {
const len = arr.length;
for (let i = 0; i < len - 1; i++) {
for (let j = 0; j < len - 1 - i; j++) {
// 比较相邻元素
if (arr[j] > arr[j + 1]) {
// 交换元素
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
return arr;
}</code></pre>
</div>
</div>
</section>
<!-- 算法列表 -->
<section id="algorithms" class="mb-16">
<h2 class="text-2xl md:text-3xl font-bold mb-8 text-center">八大排序算法</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- 冒泡排序 -->
<div class="bg-white rounded-xl shadow-md p-6 transition-all hover:shadow-lg">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center mr-3">
<i class="fa fa-arrow-down text-primary"></i>
</div>
<h3 class="text-xl font-bold">冒泡排序</h3>
</div>
<p class="text-gray-600 mb-4">冒泡排序通过重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。</p>
<div class="grid grid-cols-2 gap-2 text-sm">
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 平均时间复杂度:O(n²)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最坏时间复杂度:O(n²)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最好时间复杂度:O(n)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 空间复杂度:O(1)
</div>
<div class="flex items-center text-gray-500 col-span-2">
<i class="fa fa-check-circle text-primary mr-1"></i> 稳定性:稳定
</div>
</div>
</div>
<!-- 选择排序 -->
<div class="bg-white rounded-xl shadow-md p-6 transition-all hover:shadow-lg">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center mr-3">
<i class="fa fa-hand-pointer-o text-primary"></i>
</div>
<h3 class="text-xl font-bold">选择排序</h3>
</div>
<p class="text-gray-600 mb-4">选择排序首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。</p>
<div class="grid grid-cols-2 gap-2 text-sm">
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 平均时间复杂度:O(n²)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最坏时间复杂度:O(n²)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最好时间复杂度:O(n²)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 空间复杂度:O(1)
</div>
<div class="flex items-center text-gray-500 col-span-2">
<i class="fa fa-times-circle text-danger mr-1"></i> 稳定性:不稳定
</div>
</div>
</div>
<!-- 插入排序 -->
<div class="bg-white rounded-xl shadow-md p-6 transition-all hover:shadow-lg">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center mr-3">
<i class="fa fa-arrow-right text-primary"></i>
</div>
<h3 class="text-xl font-bold">插入排序</h3>
</div>
<p class="text-gray-600 mb-4">插入排序是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。</p>
<div class="grid grid-cols-2 gap-2 text-sm">
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 平均时间复杂度:O(n²)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最坏时间复杂度:O(n²)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最好时间复杂度:O(n)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 空间复杂度:O(1)
</div>
<div class="flex items-center text-gray-500 col-span-2">
<i class="fa fa-check-circle text-primary mr-1"></i> 稳定性:稳定
</div>
</div>
</div>
<!-- 希尔排序 -->
<div class="bg-white rounded-xl shadow-md p-6 transition-all hover:shadow-lg">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center mr-3">
<i class="fa fa-step-forward text-primary"></i>
</div>
<h3 class="text-xl font-bold">希尔排序</h3>
</div>
<p class="text-gray-600 mb-4">希尔排序是插入排序的一种更高效的改进版本。它与插入排序的不同之处在于,它会优先比较距离较远的元素。</p>
<div class="grid grid-cols-2 gap-2 text-sm">
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 平均时间复杂度:O(n^1.3)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最坏时间复杂度:O(n²)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最好时间复杂度:O(n)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 空间复杂度:O(1)
</div>
<div class="flex items-center text-gray-500 col-span-2">
<i class="fa fa-times-circle text-danger mr-1"></i> 稳定性:不稳定
</div>
</div>
</div>
<!-- 归并排序 -->
<div class="bg-white rounded-xl shadow-md p-6 transition-all hover:shadow-lg">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center mr-3">
<i class="fa fa-code-fork text-primary"></i>
</div>
<h3 class="text-xl font-bold">归并排序</h3>
</div>
<p class="text-gray-600 mb-4">归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用,将已有序的子序列合并,得到完全有序的序列。</p>
<div class="grid grid-cols-2 gap-2 text-sm">
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 平均时间复杂度:O(n log n)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最坏时间复杂度:O(n log n)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最好时间复杂度:O(n log n)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 空间复杂度:O(n)
</div>
<div class="flex items-center text-gray-500 col-span-2">
<i class="fa fa-check-circle text-primary mr-1"></i> 稳定性:稳定
</div>
</div>
</div>
<!-- 快速排序 -->
<div class="bg-white rounded-xl shadow-md p-6 transition-all hover:shadow-lg">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center mr-3">
<i class="fa fa-bolt text-primary"></i>
</div>
<h3 class="text-xl font-bold">快速排序</h3>
</div>
<p class="text-gray-600 mb-4">快速排序通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序。</p>
<div class="grid grid-cols-2 gap-2 text-sm">
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 平均时间复杂度:O(n log n)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最坏时间复杂度:O(n²)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最好时间复杂度:O(n log n)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 空间复杂度:O(log n)
</div>
<div class="flex items-center text-gray-500 col-span-2">
<i class="fa fa-times-circle text-danger mr-1"></i> 稳定性:不稳定
</div>
</div>
</div>
<!-- 堆排序 -->
<div class="bg-white rounded-xl shadow-md p-6 transition-all hover:shadow-lg">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center mr-3">
<i class="fa fa-sitemap text-primary"></i>
</div>
<h3 class="text-xl font-bold">堆排序</h3>
</div>
<p class="text-gray-600 mb-4">堆排序是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。</p>
<div class="grid grid-cols-2 gap-2 text-sm">
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 平均时间复杂度:O(n log n)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最坏时间复杂度:O(n log n)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最好时间复杂度:O(n log n)
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 空间复杂度:O(1)
</div>
<div class="flex items-center text-gray-500 col-span-2">
<i class="fa fa-times-circle text-danger mr-1"></i> 稳定性:不稳定
</div>
</div>
</div>
<!-- 基数排序 -->
<div class="bg-white rounded-xl shadow-md p-6 transition-all hover:shadow-lg">
<div class="flex items-center mb-4">
<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center mr-3">
<i class="fa fa-cubes text-primary"></i>
</div>
<h3 class="text-xl font-bold">基数排序</h3>
</div>
<p class="text-gray-600 mb-4">基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。</p>
<div class="grid grid-cols-2 gap-2 text-sm">
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 平均时间复杂度:O(d(n + r))
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最坏时间复杂度:O(d(n + r))
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 最好时间复杂度:O(d(n + r))
</div>
<div class="flex items-center text-gray-500">
<i class="fa fa-check-circle text-primary mr-1"></i> 空间复杂度:O(n + r)
</div>
<div class="flex items-center text-gray-500 col-span-2">
<i class="fa fa-check-circle text-primary mr-1"></i> 稳定性:稳定
</div>
</div>
</div>
</div>
</section>
<!-- 算法比较 -->
<section id="comparison" class="mb-16 bg-white rounded-xl shadow-lg p-6 md:p-8">
<h2 class="text-2xl md:text-3xl font-bold mb-6 text-center">排序算法比较</h2>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">排序算法</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">平均时间复杂度</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">最坏时间复杂度</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">最好时间复杂度</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">空间复杂度</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">稳定性</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">适用场景</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tr>
<td class="px-6 py-4 whitespace-nowrap font-medium">冒泡排序</td>
<td class="px-6 py-4 whitespace-nowrap">O(n²)</td>
<td class="px-6 py-4 whitespace-nowrap">O(n²)</td>
<td class="px-6 py-4 whitespace-nowrap">O(n)</td>
<td class="px-6 py-4 whitespace-nowrap">O(1)</td>
<td class="px-6 py-4 whitespace-nowrap"><span class="text-secondary"><i class="fa fa-check"></i> 稳定</span></td>
<td class="px-6 py-4 text-sm text-gray-500">数据量小或接近有序</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap font-medium">选择排序</td>
<td class="px-6 py-4 whitespace-nowrap">O(n²)</td>
<td class="px-6 py-4 whitespace-nowrap">O(n²)</td>
<td class="px-6 py-4 whitespace-nowrap">O(n²)</td>
<td class="px-6 py-4 whitespace-nowrap">O(1)</td>
<td class="px-6 py-4 whitespace-nowrap"><span class="text-danger"><i class="fa fa-times"></i> 不稳定</span></td>
<td class="px-6 py-4 text-sm text-gray-500">数据量小,对稳定性无要求</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap font-medium">插入排序</td>
<td class="px-6 py-4 whitespace-nowrap">O(n²)</td>
<td class="px-6 py-4 whitespace-nowrap">O(n²)</td>
<td class="px-6 py-4 whitespace-nowrap">O(n)</td>
<td class="px-6 py-4 whitespace-nowrap">O(1)</td>
<td class="px-6 py-4 whitespace-nowrap"><span class="text-secondary"><i class="fa fa-check"></i> 稳定</span></td>
<td class="px-6 py-4 text-sm text-gray-500">数据量小或接近有序</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap font-medium">希尔排序</td>
<td class="px-6 py-4 whitespace-nowrap">O(n^1.3)</td>
<td class="px-6 py-4 whitespace-nowrap">O(n²)</td>
<td class="px-6 py-4 whitespace-nowrap">O(n)</td>
<td class="px-6 py-4 whitespace-nowrap">O(1)</td>
<td class="px-6 py-4 whitespace-nowrap"><span class="text-danger"><i class="fa fa-times"></i> 不稳定</span></td>
<td class="px-6 py-4 text-sm text-gray-500">中等规模数据</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap font-medium">归并排序</td>
<td class="px-6 py-4 whitespace-nowrap">O(n log n)</td>
<td class="px-6 py-4 whitespace-nowrap">O(n log n)</td>
<td class="px-6 py-4 whitespace-nowrap">O(n log n)</td>
<td class="px-6 py-4 whitespace-nowrap">O(n)</td>
<td class="px-6 py-4 whitespace-nowrap"><span class="text-secondary"><i class="fa fa-check"></i> 稳定</span></td>
<td class="px-6 py-4 text-sm text-gray-500">大规模数据,要求稳定</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap font-medium">快速排序</td>
<td class="px-6 py-4 whitespace-nowrap">O(n log n)</td>
<td class="px-6 py-4 whitespace-nowrap">O(n²)</td>
<td class="px-6 py-4 whitespace-nowrap">O(n log n)</td>
<td class="px-6 py-4 whitespace-nowrap">O(log n)</td>
<td class="px-6 py-4 whitespace-nowrap"><span class="text-danger"><i class="fa fa-times"></i> 不稳定</span></td>
<td class="px-6 py-4 text-sm text-gray-500">大规模数据,平均性能好</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap font-medium">堆排序</td>
<td class="px-6 py-4 whitespace-nowrap">O(n log n)</td>
<td class="px-6 py-4 whitespace-nowrap">O(n log n)</td>
<td class="px-6 py-4 whitespace-nowrap">O(n log n)</td>
<td class="px-6 py-4 whitespace-nowrap">O(1)</td>
<td class="px-6 py-4 whitespace-nowrap"><span class="text-danger"><i class="fa fa-times"></i> 不稳定</span></td>
<td class="px-6 py-4 text-sm text-gray-500">大规模数据,内存有限</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap font-medium">基数排序</td>
<td class="px-6 py-4 whitespace-nowrap">O(d(n + r))</td>
<td class="px-6 py-4 whitespace-nowrap">O(d(n + r))</td>
<td class="px-6 py-4 whitespace-nowrap">O(d(n + r))</td>
<td class="px-6 py-4 whitespace-nowrap">O(n + r)</td>
<td class="px-6 py-4 whitespace-nowrap"><span class="text-secondary"><i class="fa fa-check"></i> 稳定</span></td>
<td class="px-6 py-4 text-sm text-gray-500">整数或字符串排序</td>
</tr>
</tbody>
</table>
</div>
</section>
<!-- 关于部分 -->
<section id="about" class="text-center max-w-3xl mx-auto">
<h2 class="text-2xl md:text-3xl font-bold mb-6">关于排序算法</h2>
<p class="text-gray-600 mb-6">排序算法是计算机科学中的基础算法,用于将一组数据按照特定顺序(通常是升序或降序)排列。选择合适的排序算法对于提高程序性能至关重要。</p>
<p class="text-gray-600 mb-6">本演示页面展示了八种经典排序算法的工作原理,包括简单排序算法(如冒泡排序、选择排序)和高效排序算法(如快速排序、归并排序)。</p>
<p class="text-gray-600">通过可视化演示,您可以直观地了解每种算法的排序过程、时间复杂度和适用场景,帮助您在实际开发中做出更合适的选择。</p>
</section>
</main>
<!-- 页脚 -->
<footer class="bg-dark text-white py-8">
<div class="container mx-auto px-4">
<div class="flex flex-col md:flex-row justify-between items-center">
<div class="mb-4 md:mb-0">
<div class="flex items-center justify-center md:justify-start">
<i class="fa fa-sort-amount-asc text-primary text-2xl mr-2"></i>
<h2 class="text-xl font-bold">八大排序算法可视化</h2>
</div>
<p class="text-gray-400 text-sm mt-2 text-center md:text-left">直观理解排序算法的工作原理</p>
</div>
<div class="flex space-x-6">
<a href="#" class="text-gray-400 hover:text-primary transition-colors">
<i class="fa fa-github text-xl"></i>
</a>
<a href="#" class="text-gray-400 hover:text-primary transition-colors">
<i class="fa fa-twitter text-xl"></i>
</a>
<a href="#" class="text-gray-400 hover:text-primary transition-colors">
<i class="fa fa-linkedin text-xl"></i>
</a>
</div>
</div>
<div class="border-t border-gray-700 mt-6 pt-6 text-center text-gray-400 text-sm">
© 2023 排序算法可视化演示 | 用直观的方式理解算法
</div>
</div>
</footer>
<script>
// 全局变量
let array = [];
let isSorting = false;
let isPaused = false;
let sortSteps = [];
let currentStep = 0;
let animationInterval;
let startTime;
let comparisonCount = 0;
let swapCount = 0;
// DOM 元素
const visualizationContainer = document.getElementById('visualizationContainer');
const algorithmSelect = document.getElementById('algorithmSelect');
const arraySize = document.getElementById('arraySize');
const arraySizeValue = document.getElementById('arraySizeValue');
const sortSpeed = document.getElementById('sortSpeed');
const sortSpeedValue = document.getElementById('sortSpeedValue');
const generateBtn = document.getElementById('generateBtn');
const sortBtn = document.getElementById('sortBtn');
const pauseBtn = document.getElementById('pauseBtn');
const resetBtn = document.getElementById('resetBtn');
const statusText = document.getElementById('statusText');
const statusIcon = document.getElementById('statusIcon');
const sortStats = document.getElementById('sortStats');
const comparisonCountEl = document.getElementById('comparisonCount');
const swapCountEl = document.getElementById('swapCount');
const timeElapsedEl = document.getElementById('timeElapsed');
const algorithmCode = document.getElementById('algorithmCode');
const mobileMenuBtn = document.getElementById('mobileMenuBtn');
const mobileMenu = document.getElementById('mobileMenu');
// 初始化
document.addEventListener('DOMContentLoaded', () => {
generateRandomArray();
updateAlgorithmCode();
// 事件监听
generateBtn.addEventListener('click', generateRandomArray);
sortBtn.addEventListener('click', startSorting);
pauseBtn.addEventListener('click', pauseSorting);
resetBtn.addEventListener('click', resetSorting);
arraySize.addEventListener('input', updateArraySize);
sortSpeed.addEventListener('input', updateSortSpeed);
algorithmSelect.addEventListener('change', updateAlgorithmCode);
mobileMenuBtn.addEventListener('click', toggleMobileMenu);
// 平滑滚动
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const targetId = this.getAttribute('href');
const targetElement = document.querySelector(targetId);
if (targetElement) {
window.scrollTo({
top: targetElement.offsetTop - 80,
behavior: 'smooth'
});
// 关闭移动菜单
if (!mobileMenu.classList.contains('hidden')) {
mobileMenu.classList.add('hidden');
}
}
});
});
});
// 生成随机数组
function generateRandomArray() {
resetSorting();
const size = parseInt(arraySize.value);
array = [];
for (let i = 0; i < size; i++) {
// 生成 1 到 100 的随机数
array.push(Math.floor(Math.random() * 100) + 1);
}
renderArray();
}
// 渲染数组
function renderArray(highlightIndices = {}, minIndex = -1) {
visualizationContainer.innerHTML = '';
array.forEach((value, index) => {
const bar = document.createElement('div');
const barHeight = `${value * 3}px`;
const barWidth = `${Math.max(4, 600 / array.length)}px`;
bar.className = 'sort-bar';
bar.style.height = barHeight;
bar.style.width = barWidth;
// 添加高亮类
if (highlightIndices.comparing && highlightIndices.comparing.includes(index)) {
bar.classList.add('sort-bar-compared');
} else if (highlightIndices.swapping && highlightIndices.swapping.includes(index)) {
bar.classList.add('sort-bar-active');
} else if (highlightIndices.sorted && highlightIndices.sorted.includes(index)) {
bar.classList.add('sort-bar-completed');
}
// 标记最小值
if (index === minIndex) {
bar.classList.add('sort-bar-min');
}
visualizationContainer.appendChild(bar);
});
}
// 更新数组大小显示
function updateArraySize() {
arraySizeValue.textContent = arraySize.value;
generateRandomArray();
}
// 更新排序速度显示
function updateSortSpeed() {
sortSpeedValue.textContent = `${sortSpeed.value}ms`;
// 如果正在排序,更新动画间隔
if (isSorting && !isPaused) {
clearInterval(animationInterval);
animationInterval = setInterval(executeNextStep, 1000 - parseInt(sortSpeed.value));
}
}
// 开始排序
function startSorting() {
if (isSorting && isPaused) {
// 从暂停状态恢复
isPaused = false;
sortBtn.disabled = true;
pauseBtn.disabled = false;
statusText.textContent = `正在排序:${getAlgorithmName()}`;
statusIcon.className = 'w-3 h-3 rounded-full bg-accent mr-2';
// 恢复动画
animationInterval = setInterval(executeNextStep, 1000 - parseInt(sortSpeed.value));
return;
}
if (isSorting) return;
// 准备排序
isSorting = true;
isPaused = false;
currentStep = 0;
comparisonCount = 0;
swapCount = 0;
sortSteps = [];
// 更新UI状态
generateBtn.disabled = true;
algorithmSelect.disabled = true;
arraySize.disabled = true;
sortBtn.disabled = true;
pauseBtn.disabled = false;
resetBtn.disabled = false;
statusText.textContent = `正在排序:${getAlgorithmName()}`;
statusIcon.className = 'w-3 h-3 rounded-full bg-accent mr-2';
sortStats.classList.remove('hidden');
comparisonCountEl.textContent = '0';
swapCountEl.textContent = '0';
timeElapsedEl.textContent = '0';
// 记录开始时间
startTime = new Date().getTime();
// 根据选择的算法生成排序步骤
switch (algorithmSelect.value) {
case 'bubble':
generateBubbleSortSteps();
break;
case 'selection':
generateSelectionSortSteps();
break;
case 'insertion':
generateInsertionSortSteps();
break;
case 'shell':
generateShellSortSteps();
break;
case 'merge':
generateMergeSortSteps();
break;
case 'quick':
generateQuickSortSteps();
break;
case 'heap':
generateHeapSortSteps();
break;
case 'radix':
generateRadixSortSteps();
break;
}
// 开始执行排序步骤
animationInterval = setInterval(executeNextStep, 1000 - parseInt(sortSpeed.value));
}
// 暂停排序
function pauseSorting() {
if (!isSorting || isPaused) return;
isPaused = true;
clearInterval(animationInterval);
// 更新UI状态
sortBtn.disabled = false;
pauseBtn.disabled = true;
statusText.textContent = `已暂停:${getAlgorithmName()}`;
statusIcon.className = 'w-3 h-3 rounded-full bg-warning mr-2';
}
// 重置排序
function resetSorting() {
if (!isSorting && currentStep === 0) return;
// 停止动画
clearInterval(animationInterval);
// 重置状态
isSorting = false;
isPaused = false;
currentStep = 0;
sortSteps = [];
// 更新UI状态
generateBtn.disabled = false;
algorithmSelect.disabled = false;
arraySize.disabled = false;
sortBtn.disabled = false;
pauseBtn.disabled = true;
resetBtn.disabled = true;
statusText.textContent = '就绪:请生成数组并选择排序算法';
statusIcon.className = 'w-3 h-3 rounded-full bg-gray-400 mr-2';
sortStats.classList.add('hidden');
// 重新渲染原始数组
renderArray();
}
// 执行下一步排序
function executeNextStep() {
if (currentStep >= sortSteps.length) {
// 排序完成
clearInterval(animationInterval);
isSorting = false;
// 所有元素标记为已排序
renderArray({ sorted: Array.from({ length: array.length }, (_, i) => i) });
// 更新UI状态
generateBtn.disabled = false;
algorithmSelect.disabled = false;
arraySize.disabled = false;
sortBtn.disabled = false;
pauseBtn.disabled = true;
statusText.textContent = `排序完成:${getAlgorithmName()}`;
statusIcon.className = 'w-3 h-3 rounded-full bg-secondary mr-2';
return;
}
// 执行当前步骤
const step = sortSteps[currentStep];
if (step.type === 'compare') {
comparisonCount++;
comparisonCountEl.textContent = comparisonCount.toString();
renderArray({ comparing: step.indices });
} else if (step.type === 'swap') {
swapCount++;
swapCountEl.textContent = swapCount.toString();
// 交换元素
[array[step.indices[0]], array[step.indices[1]]] = [array[step.indices[1]], array[step.indices[0]]];
renderArray({ swapping: step.indices });
} else if (step.type === 'markMin') {
renderArray({}, step.index);
} else if (step.type === 'markSorted') {
renderArray({ sorted: step.indices });
}
// 更新耗时
const currentTime = new Date().getTime();
timeElapsedEl.textContent = (currentTime - startTime).toString();
currentStep++;
}
// 获取算法名称
function getAlgorithmName() {
const algorithmMap = {
'bubble': '冒泡排序',
'selection': '选择排序',
'insertion': '插入排序',
'shell': '希尔排序',
'merge': '归并排序',
'quick': '快速排序',
'heap': '堆排序',
'radix': '基数排序'
};
return algorithmMap[algorithmSelect.value] || '未知算法';
}
// 更新算法代码展示
function updateAlgorithmCode() {
let code = '';
switch (algorithmSelect.value) {
case 'bubble':
code = `// 冒泡排序算法
function bubbleSort(arr) {
const len = arr.length;
for (let i = 0; i < len - 1; i++) {
// 标记是否发生交换
let swapped = false;
for (let j = 0; j < len - 1 - i; j++) {
// 比较相邻元素
if (arr[j] > arr[j + 1]) {
// 交换元素
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
swapped = true;
}
}
// 如果没有交换,说明数组已经有序
if (!swapped) break;
}
return arr;
}`;
break;
case 'selection':
code = `// 选择排序算法
function selectionSort(arr) {
const len = arr.length;
for (let i = 0; i < len - 1; i++) {
// 找到最小元素的索引
let minIndex = i;
for (let j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// 将最小元素与当前元素交换
[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
}
return arr;
}`;
break;
case 'insertion':
code = `// 插入排序算法
function insertionSort(arr) {
const len = arr.length;
for (let i = 1; i < len; i++) {
// 保存当前元素
const key = arr[i];
let j = i - 1;
// 将大于key的元素向后移动
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
// 插入key到正确位置
arr[j + 1] = key;
}
return arr;
}`;
break;
case 'shell':
code = `// 希尔排序算法
function shellSort(arr) {
const len = arr.length;
// 初始步长
let gap = Math.floor(len / 2);
// 逐渐减小步长
while (gap > 0) {
// 对每个步长进行插入排序
for (let i = gap; i < len; i++) {
const key = arr[i];
let j = i;
// 插入排序
while (j >= gap && arr[j - gap] > key) {
arr[j] = arr[j - gap];
j -= gap;
}
arr[j] = key;
}
// 减小步长
gap = Math.floor(gap / 2);
}
return arr;
}`;
break;
case 'merge':
code = `// 归并排序算法
function mergeSort(arr) {
// 基本情况:如果数组长度小于等于1,则已经排序
if (arr.length <= 1) {
return arr;
}
// 将数组分成两半
const mid = Math.floor(arr.length / 2);
const left = arr.slice(0, mid);
const right = arr.slice(mid);
// 递归排序两半并合并
return merge(mergeSort(left), mergeSort(right));
}
// 合并两个已排序的数组
function merge(left, right) {
let result = [];
let i = 0; // 左数组索引
let j = 0; // 右数组索引
// 比较两个数组的元素并合并
while (i < left.length && j < right.length) {
if (left[i] < right[j]) {
result.push(left[i]);
i++;
} else {
result.push(right[j]);
j++;
}
}
// 添加剩余元素
return result.concat(left.slice(i)).concat(right.slice(j));
}`;
break;
case 'quick':
code = `// 快速排序算法
function quickSort(arr, low = 0, high = arr.length - 1) {
if (low < high) {
// 将数组分区,获取基准元素的正确位置
const pi = partition(arr, low, high);
// 递归排序基准元素左右两边的子数组
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
return arr;
}
// 分区函数
function partition(arr, low, high) {
// 选择最右边的元素作为基准
const pivot = arr[high];
let i = low - 1; // 小于基准的元素的索引
for (let j = low; j < high; j++) {
// 如果当前元素小于或等于基准
if (arr[j] <= pivot) {
i++;
// 交换 arr[i] 和 arr[j]
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
// 交换 arr[i+1] 和 arr[high] (基准元素)
[arr[i + 1], arr[high]] = [arr[high], arr[i + 1]];
return i + 1;
}`;
break;
case 'heap':
code = `// 堆排序算法
function heapSort(arr) {
const len = arr.length;
// 构建最大堆
for (let i = Math.floor(len / 2) - 1; i >= 0; i--) {
heapify(arr, len, i);
}
// 从堆中提取元素
for (let i = len - 1; i > 0; i--) {
// 将当前根(最大值)移到数组末尾
[arr[0], arr[i]] = [arr[i], arr[0]];
// 对剩余元素调用heapify
heapify(arr, i, 0);
}
return arr;
}
// 堆化函数
function heapify(arr, n, i) {
let largest = i; // 初始化最大值为根
const left = 2 * i + 1; // 左子节点索引
const right = 2 * i + 2; // 右子节点索引
// 如果左子节点大于根
if (left < n && arr[left] > arr[largest]) {
largest = left;
}
// 如果右子节点大于当前最大值
if (right < n && arr[right] > arr[largest]) {
largest = right;
}
// 如果最大值不是根
if (largest !== i) {
[arr[i], arr[largest]] = [arr[largest], arr[i]];
// 递归堆化受影响的子树
heapify(arr, n, largest);
}
}`;
break;
case 'radix':
code = `// 基数排序算法
function radixSort(arr) {
// 找到数组中的最大值以确定最大位数
const max = Math.max(...arr);
// 对每个位数进行计数排序
// exp 是 10^i,其中 i 是当前处理的位数
for (let exp = 1; Math.floor(max / exp) > 0; exp *= 10) {
countSort(arr, exp);
}
return arr;
}
// 根据指定位数进行计数排序
function countSort(arr, exp) {
const len = arr.length;
const output = new Array(len).fill(0);
const count = new Array(10).fill(0);
// 存储每个数字出现的次数
for (let i = 0; i < len; i++) {
const digit = Math.floor(arr[i] / exp) % 10;
count[digit]++;
}
// 更改 count[i],使其包含实际位置
for (let i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
// 构建输出数组
for (let i = len - 1; i >= 0; i--) {
const digit = Math.floor(arr[i] / exp) % 10;
output[count[digit] - 1] = arr[i];
count[digit]--;
}
// 将输出数组复制到原数组
for (let i = 0; i < len; i++) {
arr[i] = output[i];
}
}`;
break;
}
algorithmCode.innerHTML = code;
}
// 切换移动菜单
function toggleMobileMenu() {
mobileMenu.classList.toggle('hidden');
}
// 生成冒泡排序步骤
function generateBubbleSortSteps() {
// 创建数组副本以避免修改原始数组
const arr = [...array];
const len = arr.length;
const sortedIndices = new Set();
for (let i = 0; i < len - 1; i++) {
let swapped = false;
for (let j = 0; j < len - 1 - i; j++) {
// 添加比较步骤
sortSteps.push({ type: 'compare', indices: [j, j + 1] });
if (arr[j] > arr[j + 1]) {
// 添加交换步骤
sortSteps.push({ type: 'swap', indices: [j, j + 1] });
// 交换元素
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
swapped = true;
}
}
// 标记最后一个元素为已排序
sortedIndices.add(len - 1 - i);
sortSteps.push({
type: 'markSorted',
indices: Array.from(sortedIndices)
});
if (!swapped) break;
}
// 标记所有元素为已排序
sortSteps.push({
type: 'markSorted',
indices: Array.from({ length: len }, (_, i) => i)
});
}
// 生成选择排序步骤
function generateSelectionSortSteps() {
const arr = [...array];
const len = arr.length;
const sortedIndices = new Set();
for (let i = 0; i < len - 1; i++) {
let minIndex = i;
// 找到最小元素的索引
for (let j = i + 1; j < len; j++) {
sortSteps.push({ type: 'compare', indices: [minIndex, j] });
if (arr[j] < arr[minIndex]) {
minIndex = j;
sortSteps.push({ type: 'markMin', index: minIndex });
}
}
// 标记当前最小值
sortSteps.push({ type: 'markMin', index: minIndex });
// 交换最小元素与当前元素
if (minIndex !== i) {
sortSteps.push({ type: 'swap', indices: [i, minIndex] });
[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
}
// 标记当前位置为已排序
sortedIndices.add(i);
sortSteps.push({
type: 'markSorted',
indices: Array.from(sortedIndices)
});
}
// 最后一个元素自动排序完成
sortedIndices.add(len - 1);
sortSteps.push({
type: 'markSorted',
indices: Array.from(sortedIndices)
});
}
// 生成插入排序步骤
function generateInsertionSortSteps() {
const arr = [...array];
const len = arr.length;
for (let i = 1; i < len; i++) {
const key = arr[i];
let j = i - 1;
// 将大于key的元素向后移动
while (j >= 0 && arr[j] > key) {
sortSteps.push({ type: 'compare', indices: [j, i] });
sortSteps.push({ type: 'swap', indices: [j + 1, j] });
arr[j + 1] = arr[j];
j--;
}
// 插入key到正确位置
if (j + 1 !== i) {
arr[j + 1] = key;
sortSteps.push({ type: 'swap', indices: [j + 1, i] });
}
// 标记已排序的元素
sortSteps.push({
type: 'markSorted',
indices: Array.from({ length: i + 1 }, (_, k) => k)
});
}
}
// 生成希尔排序步骤
function generateShellSortSteps() {
const arr = [...array];
const len = arr.length;
let gap = Math.floor(len / 2);
while (gap > 0) {
for (let i = gap; i < len; i++) {
const key = arr[i];
let j = i;
while (j >= gap && arr[j - gap] > key) {
sortSteps.push({ type: 'compare', indices: [j - gap, j] });
sortSteps.push({ type: 'swap', indices: [j, j - gap] });
arr[j] = arr[j - gap];
j -= gap;
}
if (j !== i) {
arr[j] = key;
sortSteps.push({ type: 'swap', indices: [j, i] });
}
}
gap = Math.floor(gap / 2);
}
// 标记所有元素为已排序
sortSteps.push({
type: 'markSorted',
indices: Array.from({ length: len }, (_, i) => i)
});
}
// 生成归并排序步骤
function generateMergeSortSteps() {
const arr = [...array];
const len = arr.length;
// 辅助函数:合并两个已排序的子数组
function mergeSteps(arr, left, mid, right) {
const n1 = mid - left + 1;
const n2 = right - mid;
// 创建临时数组
const L = new Array(n1);
const R = new Array(n2);
// 复制数据到临时数组
for (let i = 0; i < n1; i++) {
L[i] = arr[left + i];
}
for (let j = 0; j < n2; j++) {
R[j] = arr[mid + 1 + j];
}
// 合并临时数组
let i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
sortSteps.push({
type: 'compare',
indices: [left + i, mid + 1 + j]
});
if (L[i] <= R[j]) {
if (arr[k] !== L[i]) {
arr[k] = L[i];
sortSteps.push({
type: 'swap',
indices: [k, left + i]
});
}
i++;
} else {
arr[k] = R[j];
sortSteps.push({
type: 'swap',
indices: [k, mid + 1 + j]
});
j++;
}
k++;
}
// 复制剩余元素
while (i < n1) {
if (arr[k] !== L[i]) {
arr[k] = L[i];
sortSteps.push({
type: 'swap',
indices: [k, left + i]
});
}
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
sortSteps.push({
type: 'swap',
indices: [k, mid + 1 + j]
});
j++;
k++;
}
// 标记已排序的范围
const sorted = [];
for (let x = left; x <= right; x++) {
sorted.push(x);
}
sortSteps.push({ type: 'markSorted', indices: sorted });
}
// 递归归并排序
function mergeSortSteps(arr, left, right) {
if (left >= right) return;
const mid = left + Math.floor((right - left) / 2);
mergeSortSteps(arr, left, mid);
mergeSortSteps(arr, mid + 1, right);
mergeSteps(arr, left, mid, right);
}
mergeSortSteps(arr, 0, len - 1);
}
// 生成快速排序步骤
function generateQuickSortSteps() {
const arr = [...array];
const len = arr.length;
// 分区函数
function partitionSteps(arr, low, high) {
const pivot = arr[high];
let i = low - 1;
for (let j = low; j <= high - 1; j++) {
sortSteps.push({ type: 'compare', indices: [j, high] });
if (arr[j] < pivot) {
i++;
if (i !== j) {
[arr[i], arr[j]] = [arr[j], arr[i]];
sortSteps.push({ type: 'swap', indices: [i, j] });
}
}
}
// 将基准元素放到正确位置
if (i + 1 !== high) {
[arr[i + 1], arr[high]] = [arr[high], arr[i + 1]];
sortSteps.push({ type: 'swap', indices: [i + 1, high] });
}
// 标记基准元素为已排序
sortSteps.push({ type: 'markSorted', indices: [i + 1] });
return i + 1;
}
// 递归快速排序
function quickSortSteps(arr, low, high) {
if (low < high) {
const pi = partitionSteps(arr, low, high);
quickSortSteps(arr, low, pi - 1);
quickSortSteps(arr, pi + 1, high);
} else if (low === high) {
// 单个元素自动排序完成
sortSteps.push({ type: 'markSorted', indices: [low] });
}
}
quickSortSteps(arr, 0, len - 1);
}
// 生成堆排序步骤
function generateHeapSortSteps() {
const arr = [...array];
const len = arr.length;
// 堆化函数
function heapifySteps(arr, n, i) {
let largest = i;
const left = 2 * i + 1;
const right = 2 * i + 2;
if (left < n) {
sortSteps.push({ type: 'compare', indices: [largest, left] });
if (arr[left] > arr[largest]) {
largest = left;
}
}
if (right < n) {
sortSteps.push({ type: 'compare', indices: [largest, right] });
if (arr[right] > arr[largest]) {
largest = right;
}
}
if (largest !== i) {
[arr[i], arr[largest]] = [arr[largest], arr[i]];
sortSteps.push({ type: 'swap', indices: [i, largest] });
heapifySteps(arr, n, largest);
}
}
// 构建最大堆
for (let i = Math.floor(len / 2) - 1; i >= 0; i--) {
heapifySteps(arr, len, i);
}
// 提取元素
const sortedIndices = new Set();
for (let i = len - 1; i > 0; i--) {
[arr[0], arr[i]] = [arr[i], arr[0]];
sortSteps.push({ type: 'swap', indices: [0, i] });
sortedIndices.add(i);
sortSteps.push({ type: 'markSorted', indices: Array.from(sortedIndices) });
heapifySteps(arr, i, 0);
}
// 最后一个元素
sortedIndices.add(0);
sortSteps.push({ type: 'markSorted', indices: Array.from(sortedIndices) });
}
// 生成基数排序步骤
function generateRadixSortSteps() {
const arr = [...array];
const len = arr.length;
if (len === 0) return;
// 找到最大值
const max = Math.max(...arr);
// 对每个位数进行排序
for (let exp = 1; Math.floor(max / exp) > 0; exp *= 10) {
// 创建计数数组和输出数组
const output = new Array(len);
const count = new Array(10).fill(0);
// 计数
for (let i = 0; i < len; i++) {
const digit = Math.floor(arr[i] / exp) % 10;
count[digit]++;
}
// 计算位置
for (let i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
// 构建输出数组
for (let i = len - 1; i >= 0; i--) {
const digit = Math.floor(arr[i] / exp) % 10;
output[count[digit] - 1] = arr[i];
// 添加交换步骤
const originalIndex = i;
const newIndex = count[digit] - 1;
if (originalIndex !== newIndex) {
sortSteps.push({ type: 'compare', indices: [originalIndex, newIndex] });
sortSteps.push({ type: 'swap', indices: [originalIndex, newIndex] });
}
count[digit]--;
}
// 复制到原数组
for (let i = 0; i < len; i++) {
arr[i] = output[i];
}
// 标记当前进度
sortSteps.push({
type: 'markSorted',
indices: Array.from({ length: len }, (_, i) => i)
});
}
}
</script>
</body>
</html>