排序的概念
排序是将一组无序的数据按照某种规则(如升序或降序)重新排列的过程。排序算法是计算机科学中的基础算法,直接影响数据处理效率。根据时间复杂度、空间复杂度、稳定性等特性,排序算法可分为多种类型。
四大常见排序分类
- 插入排序:直接插入排序、希尔排序
- 选择排序:直接选择排序、堆排序
- 交换排序:冒泡排序、快速排序
- 归并排序
插入排序
直接插入排序
思想:将待排序元素插入到已排序序列的适当位置,逐步构建有序序列。
C代码实现:
void InsertSort(int* arr, int n) {
for (int i = 1; i < n; i++) {
int key = arr[i]; // 当前待插入元素
int j = i - 1; // 从已排序序列末尾开始比较
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j]; // 元素后移
j--;
}
arr[j + 1] = key; // 插入到正确位置
}
}
特性:
- 时间复杂度:O(n²)(最坏情况)
- 空间复杂度:O(1)
- 稳定性:稳定
希尔排序
思想:通过分组插入排序逐步缩小增量(预处理),最终完成整体排序(直接插入排序)。
C代码实现:
void ShellSort(int* arr, int n) {
int gap = n / 2; // 初始增量
while (gap > 0) {
for (int i = gap; i < n; i++) {
int key = arr[i];
int j = i - gap;
while (j >= 0 && arr[j] > key) {
arr[j + gap] = arr[j];
j -= gap;
}
arr[j + gap] = key;
}
gap /= 2; // 缩小增量
}
}
预处理:
思想:
先选较大步长,将数组分成多个子序列,对各子序列分别进行插入排序;之后逐步缩小步长,重复此过程,直到步长为 1,对整个数组进行最后一次插入排序,使数组有序。
步骤:

特性:
- 时间复杂度:O(n¹·³)(平均)
- 空间复杂度:O(1)
- 稳定性:不稳定
选择排序
直接选择排序
思想:每次从未排序序列中选择最小(或最大)元素,放到已排序序列末尾。
C代码实现:
void SelectSort(int* arr, int n) {
for (int i = 0; i < n - 1; i++) {
int min_idx = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[min_idx])
min_idx = j; // 更新最小值下标
}
if (min_idx != i) {
int tmp = arr[i];
arr[i] = arr[min_idx];
arr[min_idx] = tmp;
}
}
}
特性:
- 时间复杂度:O(n²)
- 空间复杂度:O(1)
- 稳定性:不稳定
堆排序
思想:利用堆数据结构(完全二叉树)选择最大/最小元素,通过反复调整堆完成排序。
C代码实现:
void AdjustHeap(int* arr, int parent, int n) {
int child = 2 * parent + 1; // 左孩子
while (child < n) {
if (child + 1 < n && arr[child] < arr[child + 1])
child++; // 选择较大的孩子
if (arr[parent] < arr[child]) {
swap(&arr[parent], &arr[child]);
parent = child;
child = 2 * parent + 1;
} else break;
}
}
void HeapSort(int* arr, int n) {
// 建堆(从最后一个非叶子节点开始调整)
for (int i = n / 2 - 1; i >= 0; i--)
AdjustHeap(arr, i, n);
// 排序
for (int i = n - 1; i > 0; i--) {
swap(&arr[0], &arr[i]); // 交换堆顶与末尾元素
AdjustHeap(arr, 0, i); // 重新调整堆
}
}
特性:
- 时间复杂度:O(n log n)
- 空间复杂度:O(1)
- 稳定性:不稳定
交换排序
冒泡排序
思想:通过相邻元素比较和交换,将最大(或最小)元素逐步“冒泡”到序列末尾。
C代码实现:
void BubbleSort(int* arr, int n) {
for (int i = 0; i < n - 1; i++) {
int flag = 0; // 优化:记录是否发生交换
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
swap(&arr[j], &arr[j + 1]);
flag = 1;
}
}
if (!flag) break; // 无交换则提前结束
}
}
特性:
- 时间复杂度:O(n²)(优化后最好情况O(n))
- 空间复杂度:O(1)
- 稳定性:稳定
快速排序
Hoare版本
思想:选定基准值(通常为首元素),通过双指针从两端向中间扫描并交换,最终将序列分为两部分递归排序。
C代码实现:
int PartitionHoare(int* arr, int left, int right) {
int pivot = arr[left];
int i = left, j = right;
while (i < j) {
while (i < j && arr[j] >= pivot) j--;
while (i < j && arr[i] <= pivot) i++;
if (i < j) swap(&arr[i], &arr[j]);
}
swap(&arr[left], &arr[i]);
return i;
}
void QuickSortHoare(int* arr, int left, int right) {
if (left >= right) return;
int pos = PartitionHoare(arr, left, right);
QuickSortHoare(arr, left, pos - 1);
QuickSortHoare(arr, pos + 1, right);
}
挖坑法
思想:将基准值视为“坑”,通过填坑和挖坑完成分区。
C代码实现:
int PartitionHole(int* arr, int left, int right) {
int pivot = arr[left];
while (left < right) {
while (left < right && arr[right] >= pivot) right--;
arr[left] = arr[right]; // 右端填左坑
while (left < right && arr[left] <= pivot) left++;
arr[right] = arr[left]; // 左端填右坑
}
arr[left] = pivot; // 基准值填入最终坑位
return left;
}
Lomuto前后指针法
思想:使用单指针遍历数组,将小于基准值的元素交换到前部。
C代码实现:
int PartitionLomuto(int* arr, int left, int right) {
int pivot = arr[right];
int i = left - 1;
for (int j = left; j < right; j++) {
if (arr[j] < pivot) {
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[right]);
return i + 1;
}
非递归版本
思想:利用栈模拟递归过程,避免递归调用栈溢出。
C代码实现:
#include <stack>
void QuickSortNonRecursive(int* arr, int left, int right) {
std::stack<int> st;
st.push(left);
st.push(right);
while (!st.empty()) {
int r = st.top(); st.pop();
int l = st.top(); st.pop();
int pos = PartitionHoare(arr, l, r);
if (pos - 1 > l) {
st.push(l);
st.push(pos - 1);
}
if (pos + 1 < r) {
st.push(pos + 1);
st.push(r);
}
}
}
特性:
- 时间复杂度:O(n log n)(平均),O(n²)(最坏)
- 空间复杂度:O(log n)(递归栈)
- 稳定性:不稳定
归并排序
思想:分治法,将序列递归拆分为子序列,合并时按顺序拼接。
C代码实现:
void Merge(int* arr, int left, int mid, int right) {
int* tmp = (int*)malloc((right - left + 1) * sizeof(int));
int i = left, j = mid + 1, k = 0;
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) tmp[k++] = arr[i++];
else tmp[k++] = arr[j++];
}
while (i <= mid) tmp[k++] = arr[i++];
while (j <= right) tmp[k++] = arr[j++];
for (int p = 0; p < k; p++) arr[left + p] = tmp[p];
free(tmp);
}
void MergeSort(int* arr, int left, int right) {
if (left >= right) return;
int mid = (left + right) / 2;
MergeSort(arr, left, mid);
MergeSort(arr, mid + 1, right);
Merge(arr, left, mid, right);
}
特性:
- 时间复杂度:O(n log n)
- 空间复杂度:O(n)(临时数组)
- 稳定性:稳定

2849

被折叠的 条评论
为什么被折叠?



