在上一章中,我们详细地探讨了插入排序(歪说基础算法6-1:魔法系列:我们一起搅动魔法锅,揭秘插入排序!)——一种依赖于元素位置的简单但却具有一定效率的排序方式。现在,我们要转到另一种简单但重要的排序方式:选择排序。
选择排序——轮盘赌的背后
试想一下,你在和朋友们进行轮盘赌。每一轮你都会选出你认为最可能赢得游戏的朋友。你根据他们的技能,他们之前的表现,甚至你的直觉来做出决定。在这个过程中,你其实在进行一个现实版的选择排序。选择排序的整个思想就是每一轮中都选择出剩余元素中的最小(或最大)元素。
选择排序的基本步骤可以概括为:
- 找出数组中的最小值。
- 将最小值与数组的第一个元素交换位置。
- 在剩下的元素中找出最小值。
- 将这个最小值与数组的第二个元素交换位置。
- 重复以上步骤,直到整个数组排序完成。
伪代码
function selectionSort(arr)
for i from 0 to n-1
find smallest element in arr[i..n-1]
swap smallest with arr[i]
复杂度分析——为什么要避免“放飞自我”
让我们深入到选择排序的“内心世界”。首先,这种排序方式在最好、最坏和平均情况下的时间复杂度都是O(n^2),其中n是要排序的元素数量。这是因为无论输入的顺序如何,选择排序都要对每个元素进行比较。
然而,虽然选择排序的时间复杂度相对较高,但它的空间复杂度却是O(1)。这是因为这种排序方式只需要一个额外的空间来存储临时数据(例如,交换元素时的临时变量)。这意味着,对于内存有限的系统,选择排序可能是一个不错的选择。
选择排序和堆排序——当选择排序遇上二叉堆
现在,你可能在想,既然选择排序的时间复杂度那么高,那么我们有没有办法改进它呢?答案是有的,这就是我们要介绍的堆排序。
堆排序是选择排序的一种改进。它的基本思想是利用堆这种数据结构来找出剩余元素中的最大(或最小)元素。我们首先将待排序的元素建立成一个大顶堆(或小顶堆),然后将堆顶元素(即最大或最小元素)与最后一个元素交换,然后将剩余的元素再调整为大顶堆(或小顶堆),重复这个过程,直到整个数组排序完成。
伪代码
pseudocodeCopy codefunction heapSort(arr)
buildMaxHeap(arr)
for i from n to 1
swap arr[0] with arr[i]
heapify(arr, 0, i)
这就是选择排序和堆排序的基本原理。接下来,让我们用C++实现一下简单的选择排序,并通过一个实例来解释这个过程。
选择排序——C++实现和详细解释
在我们开始编写代码之前,让我们首先来设定一个任务。我们有一堆数字,需要将它们从小到大排序,这些数字是:10, 25, 12, 22, 11。
接下来,让我们使用C++来实现选择排序:
#include
using namespace std;
void swap(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
void selectionSort(int arr[], int n) {
int i, j, min_index;
for(i = 0; i < n-1; i++) {
min_index = i;
for(j = i+1; j < n; j++)
if(arr[j] < arr[min_index])
min_index = j;
swap(arr[min_index], arr[i]);
}
}
void printArray(int arr[], int n) {
int i;
for(i = 0; i < n; i++)
cout << arr[i] << " ";
cout << endl;
}
int main() {
int arr[] = {10, 25, 12, 22, 11};
int n = sizeof(arr)/sizeof(arr[0]);
selectionSort(arr, n);
cout<<"Sorted array: \n";
printArray(arr, n);
return 0;
}
这个程序首先定义了一个交换函数swap,它交换两个整数的值。然后定义了选择排序函数selectionSort,它首先找出数组中的最小元素,然后将这个最小元素与数组的第一个元素交换,重复这个过程直到整个数组排序完成。最后,我们用printArray函数打印出排序后的数组。
这个程序的输出将是:
Sorted array:
10 11 12 22 25
就这样,我们用选择排序成功地将一个数组排序了。下一章,我们将继续探讨排序的世界,看看更复杂,更高效的排序算法!