排序算法是计算机科学中的基本算法之一,用于将数据按特定顺序排列。不同的排序算法有不同的实现方式和效率。下面我将通俗易懂地讲解几种常见的排序算法,包括冒泡排序、选择排序、插入排序、归并排序和快速排序。
1. 冒泡排序(Bubble Sort)
冒泡排序 是一种简单的排序算法,其工作原理是通过重复比较相邻的元素并交换位置,使得每一趟遍历都将当前最大(或最小)的元素“冒泡”到数组的一端。
步骤:
- 从头到尾遍历数组:比较相邻的两个元素。
- 交换:如果前一个元素比后一个元素大,则交换它们的位置。
- 重复:对整个数组重复步骤 1 和 2,直到没有更多需要交换的元素为止。
代码实现:
function bubbleSort(arr) {
const n = arr.length;
for (let i = 0; i < n - 1; i++) {
for (let j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; // 交换
}
}
}
return arr;
}
// 示例
const array = [5, 3, 8, 4, 2];
console.log(bubbleSort(array)); // 输出: [2, 3, 4, 5, 8]
2. 选择排序(Selection Sort)
选择排序 的核心思想是每一轮从未排序部分中选择最小(或最大)元素,并将其放到已排序部分的末尾。
步骤:
- 找到最小元素:遍历未排序部分的所有元素,找到最小的那个元素。
- 交换:将最小元素与未排序部分的第一个元素交换。
- 缩小未排序部分:标记第一个元素为已排序部分的末尾,然后继续处理剩下的元素。
代码实现:
function selectionSort(arr) {
const 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;
}
// 示例
const array = [64, 25, 12, 22, 11];
console.log(selectionSort(array)); // 输出: [11, 12, 22, 25, 64]
3. 插入排序(Insertion Sort)
插入排序 是一种简单的排序算法,它的基本思想是将未排序的元素插入到已排序的部分中,直到整个数组有序。
步骤:
- 从第二个元素开始:将其视为当前元素。
- 与已排序部分比较:将当前元素与已排序部分的元素从后向前比较,找到适当的插入位置。
- 插入:将当前元素插入到找到的位置。
代码实现:
function insertionSort(arr) {
const n = arr.length;
for (let i = 1; i < n; i++) {
let key = arr[i];
let j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j]; // 移动元素
j--;
}
arr[j + 1] = key; // 插入元素
}
return arr;
}
// 示例
const array = [12, 11, 13, 5, 6];
console.log(insertionSort(array)); // 输出: [5, 6, 11, 12, 13]
4. 归并排序(Merge Sort)
归并排序 是一种基于分治法的排序算法,将数组分为两半,分别排序后再合并。
步骤:
- 分割:将数组递归地分成两半,直到每个部分只包含一个元素。
- 合并:将已排序的部分合并成一个有序的数组。
代码实现:
function mergeSort(arr) {
if (arr.length <= 1) return arr;
const middle = Math.floor(arr.length / 2);
const left = arr.slice(0, middle);
const right = arr.slice(middle);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right) {
let result = [];
let leftIndex = 0;
let rightIndex = 0;
while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] < right[rightIndex]) {
result.push(left[leftIndex]);
leftIndex++;
} else {
result.push(right[rightIndex]);
rightIndex++;
}
}
return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex));
}
// 示例
const array = [38, 27, 43, 3, 9, 82, 10];
console.log(mergeSort(array)); // 输出: [3, 9, 10, 27, 38, 43, 82]
5. 快速排序(Quick Sort)
快速排序 是一种分治排序算法,通过选择一个“基准”元素,将数组分成比基准小和大的两部分,递归地对这两部分进行排序。
步骤:
- 选择基准:通常选择数组的第一个元素或最后一个元素作为基准。
- 分割:将数组分成两个部分,一部分的所有元素都小于基准,另一部分都大于基准。
- 递归排序:递归地对这两个部分进行排序。
代码实现:
function quickSort(arr) {
if (arr.length <= 1) return arr;
const pivot = arr[arr.length - 1];
const left = [];
const right = [];
for (let i = 0; i < arr.length - 1; i++) {
if (arr[i] < pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return [...quickSort(left), pivot, ...quickSort(right)];
}
// 示例
const array = [10, 7, 8, 9, 1, 5];
console.log(quickSort(array)); // 输出: [1, 5, 7, 8, 9, 10]
总结
- 冒泡排序:简单易懂,但效率低。
- 选择排序:每轮选择最小元素,简单且直观。
- 插入排序:适合小规模数据和部分排序的数据。
- 归并排序:高效的分治算法,稳定排序,但需要额外的空间。
- 快速排序:平均情况下非常高效,但在最坏情况下表现较差。
这些排序算法有各自的优缺点,适用于不同的场景。通过选择合适的算法,可以提高程序的性能和效率。