02-八大排序可视化
<!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">
                &copy; 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>

posted on 2025-09-28 14:46  笨忠  阅读(12)  评论(0)    收藏  举报