选择排序是一种简单直观的排序算法,非常适合编程入门者学习。它的基本思想是:每次找出数组中最小(或最大)的元素,然后将其放到数组的起始位置,接着再从剩余未排序的元素中寻找最小(或最大)的元素,放到已排序序列的末尾,依此类推,直到所有元素排序完毕。

一、核心思想:"逐个挑选,放到对应位置"
选择排序的逻辑就像我们日常生活中整理书架 的过程 ------ 假设要把一摞杂乱的书按厚度从薄到厚排列,我们会先从所有书中找出最薄的那本,放到书架的第一个位置;接着从剩下的书中再找出最薄的,放到第二个位置;以此类推,直到所有书都排列整齐。
用算法的语言来描述,选择排序的核心思想可以概括为两点:
划分区间:将待排序数组分为 "已排序区间" 和 "未排序区间"。初始时,已排序区间为空,未排序区间为整个数组。
选择与交换:在每一轮排序中,从 "未排序区间" 里找到最小(或最大,取决于排序方向)的元素,将其与 "未排序区间" 的第一个元素交换位置,此时该元素就进入了 "已排序区间"。重复这一步骤,直到未排序区间为空。
举个具体的例子:
对数组 [64, 25, 12, 22, 11] 进行升序排序,选择排序的过程如下:
初始状态:已排序区间 [],未排序区间 [64, 25, 12, 22, 11]
第 1 轮:找到未排序区间最小元素 11,与第一个元素 64 交换 → 数组变为 [11, 25, 12, 22, 64],已排序区间 [11]
第 2 轮:从剩余未排序区间 [25, 12, 22, 64] 中找到最小元素 12,与未排序区间第一个元素 25 交换 → 数组变为 [11, 12, 25, 22, 64],已排序区间 [11, 12]
第 3 轮:从剩余未排序区间 [25, 22, 64] 中找到最小元素 22,与未排序区间第一个元素 25 交换 → 数组变为 [11, 12, 22, 25, 64],已排序区间 [11, 12, 22]
第 4 轮:从剩余未排序区间 [25, 64] 中找到最小元素 25,无需交换(本身就在未排序区间第一个位置)→ 数组不变,已排序区间 [11, 12, 22, 25, 64],排序完成
从过程中能看出,选择排序的 选择 体现在找最小元素 ,排序 体现在交换到对应位置。
二、代码实现
js
// 选择排序函数
// 参数:需要排序的数组
function selectionSort(arr) {
// 获取数组长度
const length = arr.length;
// 外层循环:控制需要排序的轮数
// 每一轮会确定一个位置的正确元素
for (let i = 0; i < length - 1; i++) {
// 假设当前轮次的第一个元素是最小值
let minIndex = i;
// 内层循环:寻找当前未排序部分的最小值
// 从i+1开始,因为i之前的元素已经排好序了
for (let j = i + 1; j < length; j++) {
// 如果找到更小的元素,更新最小值的索引
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// 如果最小值不是当前位置的元素,则交换它们
if (minIndex !== i) {
let temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
// 打印每一轮排序后的结果,方便观察排序过程
console.log(`第 ${i+1}轮排序后:`, [...arr]);
}
// 返回排序后的数组
return arr;
}
// 测试案例
const numbers = [64, 25, 12, 22, 11];
console.log("原始数组:", numbers);
// 调用选择排序函数
const sortedNumbers = selectionSort(numbers);
// 输出排序结果
console.log("排序后数组:", sortedNumbers);
//原始数组: [64, 25, 12, 22, 11]
//第1轮排序后: [11, 25, 12, 22, 64]
//第2轮排序后: [11, 12, 25, 22, 64]
//第3轮排序后: [11, 12, 22, 25, 64]
//第4轮排序后: [11, 12, 22, 25, 64]
//排序后数组: [11, 12, 22, 25, 64]
算法复杂度分析
选择排序的时间复杂度和空间复杂度都比较固定,具体分析如下:
时间复杂度:无论数组是否有序,都需要遍历 "未排序区间" 找最小值,因此最好、最坏、平均时间复杂度均为 O(n²)(n 为数组长度)。这是选择排序的最大缺点 ------ 即使面对已排序数组,也无法减少遍历次数。
空间复杂度:排序过程中仅使用了 min_index、temp 等少量临时变量,未使用额外的数组或数据结构,因此空间复杂度为 O(1),属于 "原地排序" 算法。
选择排序的应用场景
-
小规模数据排序
-
内存资源有限的场景
选择排序可视化
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>选择排序可视化</title>
<style>
body {
font-family: 'Arial', sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
line-height: 1.6;
}
.array-container {
display: flex;
margin: 20px 0;
justify-content: center;
}
.array-element {
width: 50px;
height: 50px;
background-color: #4CAF50;
color: white;
display: flex;
align-items: center;
justify-content: center;
margin: 0 5px;
border-radius: 5px;
font-weight: bold;
transition: all 0.3s ease;
}
.current-min {
background-color: #FF9800;
}
.sorted {
background-color: #2196F3;
}
.comparing {
background-color: #f44336;
}
.code-block {
background-color: #f5f5f5;
padding: 15px;
border-radius: 5px;
margin: 15px 0;
overflow-x: auto;
}
button {
background-color: #4CAF50;
color: white;
border: none;
padding: 10px 15px;
margin: 5px;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
.explanation {
background-color: #e7f3ff;
padding: 15px;
border-left: 4px solid #2196F3;
margin: 15px 0;
}
</style>
</head>
<body>
<h1>选择排序可视化教程</h1>
<div class="explanation">
<h3>选择排序的核心思想:</h3>
<p>每次循环找到最小的元素,然后把它放到正确的位置上。</p>
<p>就像整理扑克牌:每次从手中找到最小的牌,然后按顺序放好。</p>
</div>
<div class="code-block">
<h3>选择排序JavaScript代码:</h3>
<pre><code>
function selectionSort(arr) {
let n = arr.length;
// 外层循环控制排序的轮数
for (let i = 0; i < n - 1; i++) {
// 假设当前轮次的第一个元素是最小的
let minIndex = i;
// 内层循环在未排序部分中寻找最小的元素
for (let j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j; // 更新最小元素的索引
}
}
// 将找到的最小元素与当前轮次的第一个元素交换
if (minIndex !== i) {
[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
}
}
return arr;
}
</code></pre>
</div>
<h3>可视化演示:</h3>
<div id="array-container" class="array-container"></div>
<div>
<button onclick="startVisualization()">开始演示</button>
<button onclick="resetArray()">重置数组</button>
<button onclick="stepByStep()">单步执行</button>
</div>
<div id="status" style="margin-top: 15px; font-weight: bold;"></div>
<div class="explanation">
<h3>算法步骤详解:</h3>
<ol>
<li>从第一个元素开始,假设它是最小的</li>
<li>与后面的所有元素比较,找到真正的最小元素</li>
<li>将最小元素与第一个元素交换位置</li>
<li>对剩下的未排序元素重复上述过程</li>
</ol>
</div>
<script>
// 初始数组
let array = [64, 25, 12, 22, 11];
let originalArray = [...array];
// 算法状态
let currentStep = 0;
let i = 0;
let j = 0;
let minIndex = 0;
let isSorting = false;
let isCompleted = false;
// 渲染数组到页面
function renderArray(highlightIndexes = {}, status = "") {
const container = document.getElementById('array-container');
container.innerHTML = '';
array.forEach((value, index) => {
const element = document.createElement('div');
element.className = 'array-element';
element.textContent = value;
if (index < i) {
element.classList.add('sorted');
} else if (index === highlightIndexes.currentMin) {
element.classList.add('current-min');
} else if (index === highlightIndexes.comparing) {
element.classList.add('comparing');
}
container.appendChild(element);
});
document.getElementById('status').textContent = status;
}
// 初始化渲染
renderArray({}, "点击'开始演示'按钮观看选择排序过程");
// 开始可视化演示
function startVisualization() {
if (isCompleted) {
resetArray();
}
isSorting = true;
currentStep = 0;
i = 0;
j = 0;
minIndex = 0;
const sortInterval = setInterval(() => {
if (!performStep()) {
clearInterval(sortInterval);
isSorting = false;
isCompleted = true;
}
}, 1000);
}
// 单步执行
function stepByStep() {
if (isCompleted) {
resetArray();
}
performStep();
}
// 执行一步排序
function performStep() {
const n = array.length;
if (i < n - 1) {
if (currentStep === 0) {
// 步骤1: 初始化minIndex为当前i
minIndex = i;
j = i + 1;
renderArray({ currentMin: minIndex }, `第 ${i + 1}轮: 设置最小值为位置 ${i}的元素(${array[i]})`);
currentStep = 1;
return true;
} else if (currentStep === 1 && j < n) {
// 步骤2: 比较当前元素与最小值
if (array[j] < array[minIndex]) {
minIndex = j;
renderArray({ currentMin: minIndex, comparing: j }, `第 ${i + 1}轮: 发现更小的值 ${array[j]},更新最小值为位置 ${j}`);
} else {
renderArray({ currentMin: minIndex, comparing: j }, `第 ${i + 1}轮: 比较位置 ${j}的值 ${array[j]},当前最小值仍是 ${array[minIndex]}`);
}
j++;
if (j >= n) {
currentStep = 2;
}
return true;
} else if (currentStep === 2) {
// 步骤3: 交换元素
if (minIndex !== i) {
[array[i], array[minIndex]] = [array[minIndex], array[i]];
renderArray({}, `第 ${i + 1}轮: 交换位置 ${i}和位置 ${minIndex}的元素`);
} else {
renderArray({}, `第 ${i + 1}轮: 最小值已在正确位置,无需交换`);
}
i++;
currentStep = 0;
return true;
}
} else {
renderArray({}, "排序完成!");
return false;
}
}
// 重置数组
function resetArray() {
array = [...originalArray];
currentStep = 0;
i = 0;
j = 0;
minIndex = 0;
isSorting = false;
isCompleted = false;
renderArray({}, "数组已重置,点击'开始演示'按钮观看选择排序过程");
}
</script>
</body>
</html>
各位互联网搭子,要是这篇文章成功引起了你的注意,别犹豫,关注、点赞、评论、分享走一波,让我们把这份默契延续下去,一起在知识的海洋里乘风破浪!