排序是把数据按关键字从小到大(或从大到小)重新排列的过程。若排序对象能全部放进内存,称为内部排序;否则需要借助外存,称外部排序。
稳定性:若关键字相等的两个元素在排序后相对次序不变,则称该排序算法稳定,否则不稳定。判断方法:排序过程中,相等的元素是否会交换相对位置。注意稳定性与「值相同」无关,只与「相对顺序是否保持」有关。
内部排序按基本思想分四类:
gap 分组做插入排序,增量逐渐缩小到 1。不稳定。基数排序(简述):不比较关键字本身,而是按位(个位、十位、百位…)进行多趟「分配—收集」,配合队列/桶实现。适合关键字可以拆成若干「位」的数据(如整数、字符串)。时间复杂度 O(d(n+r)),d 为位数,r 为基数;稳定。
key=a[i],j=i-1 向前扫,a[j]>key 就后移,最后 a[j+1]=key。gap=n/2 递减,对每个 gap 子序列做插入排序(j>=gap && a[j-gap]>key 时跳步移动)。a[j]>a[j+1] 交换;某趟无交换即已有序。pivot=a[lo] 挖坑,右指针找小填左、左指针找大填右,两指针相遇处放回枢轴,返回枢轴位置。minIdx,与 a[i] 交换。n/2-1 向下调整成大根堆),然后反复「堆顶与末尾交换 → 对剩余部分调整」。merge 用辅助数组把两个有序区间合并;mergeSort 递归分到单元素再向上合并。下表为内部排序算法的完整对比(n 为元素个数,d 为基数排序位数,r 为基数):
| 算法 | 平均 | 最坏 | 最好 | 空间 | 稳定性 |
|---|---|---|---|---|---|
| 直接插入排序 | O(n²) | O(n²) | O(n) | O(1) | 稳定 |
| 折半插入排序 | O(n²) | O(n²) | O(n) | O(1) | 稳定 |
| 希尔排序 | O(n^1.3)(与增量序列有关) | O(n²)(取决于增量) | O(n) | O(1) | 不稳定 |
| 冒泡排序 | O(n²) | O(n²) | O(n) | O(1) | 稳定 |
| 快速排序 | O(n log n) | O(n²) | O(n log n) | O(log n)(递归栈,最坏 O(n)) | 不稳定 |
| 简单选择排序 | O(n²) | O(n²) | O(n²) | O(1) | 不稳定 |
| 堆排序 | O(n log n) | O(n log n) | O(n log n) | O(1) | 不稳定 |
| 二路归并排序 | O(n log n) | O(n log n) | O(n log n) | O(n) | 稳定 |
| 基数排序 | O(d(n+r)) | O(d(n+r)) | O(d(n+r)) | O(n+r) | 稳定 |
要点记忆:
以下四种实现完全等价,均包含 7 种排序算法:直接插入、希尔、冒泡、快速(挖坑法)、简单选择、堆排序、二路归并排序。main 中对同一份原始数组 {49, 38, 65, 97, 76, 13, 27, 49} 分别调用每种排序并打印结果,方便对比各语言写法。
#include <stdio.h>
#include <stdlib.h>
// 打印数组
void printArray(int a[], int n) {
for (int i = 0; i < n; i++) printf("%d ", a[i]);
printf("\n");
}
// 1. 直接插入排序(稳定)
void insertionSort(int a[], int n) {
for (int i = 1; i < n; i++) {
int key = a[i];
int j = i - 1;
while (j >= 0 && a[j] > key) { // 从后往前找插入位置并后移
a[j + 1] = a[j];
j--;
}
a[j + 1] = key;
}
}
// 2. 希尔排序(不稳定)
void shellSort(int a[], int n) {
for (int gap = n / 2; gap > 0; gap /= 2) { // 增量序列递减
for (int i = gap; i < n; i++) { // 对每个子序列做插入排序
int key = a[i];
int j = i;
while (j >= gap && a[j - gap] > key) {
a[j] = a[j - gap];
j -= gap;
}
a[j] = key;
}
}
}
// 3. 冒泡排序(稳定,带提前结束标志)
void bubbleSort(int a[], int n) {
for (int i = 0; i < n - 1; i++) {
int swapped = 0;
for (int j = 0; j < n - 1 - i; j++) {
if (a[j] > a[j + 1]) {
int t = a[j]; a[j] = a[j + 1]; a[j + 1] = t;
swapped = 1;
}
}
if (!swapped) break; // 本趟无交换,已经有序
}
}
// 4. 快速排序(挖坑法分区,不稳定)
int partition(int a[], int lo, int hi) {
int pivot = a[lo]; // 挖坑:取出枢轴值
while (lo < hi) {
while (lo < hi && a[hi] >= pivot) hi--; // 从右找比枢轴小的
a[lo] = a[hi]; // 填到左边的坑
while (lo < hi && a[lo] <= pivot) lo++; // 从左找比枢轴大的
a[hi] = a[lo]; // 填到右边的坑
}
a[lo] = pivot; // 枢轴归位
return lo;
}
void quickSort(int a[], int lo, int hi) {
if (lo < hi) {
int p = partition(a, lo, hi);
quickSort(a, lo, p - 1);
quickSort(a, p + 1, hi);
}
}
// 5. 简单选择排序(不稳定)
void selectionSort(int a[], int n) {
for (int i = 0; i < n - 1; i++) {
int minIdx = i;
for (int j = i + 1; j < n; j++)
if (a[j] < a[minIdx]) minIdx = j;
if (minIdx != i) {
int t = a[i]; a[i] = a[minIdx]; a[minIdx] = t;
}
}
}
// 6. 堆排序(不稳定):对以 i 为根的子树调整为大根堆
void heapify(int a[], int n, int i) {
int largest = i;
int l = 2 * i + 1;
int r = 2 * i + 2;
if (l < n && a[l] > a[largest]) largest = l;
if (r < n && a[r] > a[largest]) largest = r;
if (largest != i) {
int t = a[i]; a[i] = a[largest]; a[largest] = t;
heapify(a, n, largest); // 递归向下调整
}
}
void heapSort(int a[], int n) {
for (int i = n / 2 - 1; i >= 0; i--) heapify(a, n, i); // 建大根堆
for (int i = n - 1; i > 0; i--) { // 依次取堆顶
int t = a[0]; a[0] = a[i]; a[i] = t; // 堆顶换到末尾
heapify(a, i, 0); // 重新调整
}
}
// 7. 二路归并排序(稳定):合并两个有序区间 [lo,mid] 与 [mid+1,hi]
void merge(int a[], int lo, int mid, int hi) {
int len = hi - lo + 1;
int *tmp = (int *)malloc(sizeof(int) * len);
int i = lo, j = mid + 1, k = 0;
while (i <= mid && j <= hi) tmp[k++] = (a[i] <= a[j]) ? a[i++] : a[j++];
while (i <= mid) tmp[k++] = a[i++];
while (j <= hi) tmp[k++] = a[j++];
for (int m = 0; m < len; m++) a[lo + m] = tmp[m];
free(tmp);
}
void mergeSort(int a[], int lo, int hi) {
if (lo < hi) {
int mid = lo + (hi - lo) / 2;
mergeSort(a, lo, mid);
mergeSort(a, mid + 1, hi);
merge(a, lo, mid, hi);
}
}
// 拷贝数组,保证每次排序都从同一份原始数据开始
void copyArray(int src[], int dst[], int n) {
for (int i = 0; i < n; i++) dst[i] = src[i];
}
int main() {
int original[] = {49, 38, 65, 97, 76, 13, 27, 49};
int n = sizeof(original) / sizeof(original[0]);
int *a = (int *)malloc(sizeof(int) * n);
copyArray(original, a, n); insertionSort(a, n); printf("直接插入排序: "); printArray(a, n);
copyArray(original, a, n); shellSort(a, n); printf("希尔排序: "); printArray(a, n);
copyArray(original, a, n); bubbleSort(a, n); printf("冒泡排序: "); printArray(a, n);
copyArray(original, a, n); quickSort(a, 0, n - 1); printf("快速排序: "); printArray(a, n);
copyArray(original, a, n); selectionSort(a, n); printf("简单选择排序: "); printArray(a, n);
copyArray(original, a, n); heapSort(a, n); printf("堆排序: "); printArray(a, n);
copyArray(original, a, n); mergeSort(a, 0, n - 1); printf("归并排序: "); printArray(a, n);
free(a);
return 0;
}
#include <iostream>
#include <vector>
using namespace std;
// 打印数组
void printArray(const vector<int>& a) {
for (int x : a) cout << x << " ";
cout << endl;
}
// 1. 直接插入排序(稳定)
void insertionSort(vector<int>& a) {
int n = (int)a.size();
for (int i = 1; i < n; i++) {
int key = a[i], j = i - 1;
while (j >= 0 && a[j] > key) { a[j + 1] = a[j]; j--; }
a[j + 1] = key;
}
}
// 2. 希尔排序(不稳定)
void shellSort(vector<int>& a) {
int n = (int)a.size();
for (int gap = n / 2; gap > 0; gap /= 2) {
for (int i = gap; i < n; i++) {
int key = a[i], j = i;
while (j >= gap && a[j - gap] > key) { a[j] = a[j - gap]; j -= gap; }
a[j] = key;
}
}
}
// 3. 冒泡排序(稳定,带提前结束标志)
void bubbleSort(vector<int>& a) {
int n = (int)a.size();
for (int i = 0; i < n - 1; i++) {
bool swapped = false;
for (int j = 0; j < n - 1 - i; j++)
if (a[j] > a[j + 1]) { swap(a[j], a[j + 1]); swapped = true; }
if (!swapped) break;
}
}
// 4. 快速排序(挖坑法,不稳定)
int partition(vector<int>& a, int lo, int hi) {
int pivot = a[lo]; // 挖坑
while (lo < hi) {
while (lo < hi && a[hi] >= pivot) hi--;
a[lo] = a[hi];
while (lo < hi && a[lo] <= pivot) lo++;
a[hi] = a[lo];
}
a[lo] = pivot;
return lo;
}
void quickSort(vector<int>& a, int lo, int hi) {
if (lo < hi) {
int p = partition(a, lo, hi);
quickSort(a, lo, p - 1);
quickSort(a, p + 1, hi);
}
}
// 5. 简单选择排序(不稳定)
void selectionSort(vector<int>& a) {
int n = (int)a.size();
for (int i = 0; i < n - 1; i++) {
int minIdx = i;
for (int j = i + 1; j < n; j++)
if (a[j] < a[minIdx]) minIdx = j;
if (minIdx != i) swap(a[i], a[minIdx]);
}
}
// 6. 堆排序(不稳定)
void heapify(vector<int>& a, int n, int i) {
int largest = i, l = 2 * i + 1, r = 2 * i + 2;
if (l < n && a[l] > a[largest]) largest = l;
if (r < n && a[r] > a[largest]) largest = r;
if (largest != i) { swap(a[i], a[largest]); heapify(a, n, largest); }
}
void heapSort(vector<int>& a) {
int n = (int)a.size();
for (int i = n / 2 - 1; i >= 0; i--) heapify(a, n, i); // 建大根堆
for (int i = n - 1; i > 0; i--) { swap(a[0], a[i]); heapify(a, i, 0); }
}
// 7. 二路归并排序(稳定)
void merge(vector<int>& a, int lo, int mid, int hi) {
vector<int> tmp(hi - lo + 1);
int i = lo, j = mid + 1, k = 0;
while (i <= mid && j <= hi) tmp[k++] = (a[i] <= a[j]) ? a[i++] : a[j++];
while (i <= mid) tmp[k++] = a[i++];
while (j <= hi) tmp[k++] = a[j++];
for (int m = 0; m < (int)tmp.size(); m++) a[lo + m] = tmp[m];
}
void mergeSort(vector<int>& a, int lo, int hi) {
if (lo < hi) {
int mid = lo + (hi - lo) / 2;
mergeSort(a, lo, mid);
mergeSort(a, mid + 1, hi);
merge(a, lo, mid, hi);
}
}
int main() {
vector<int> original = {49, 38, 65, 97, 76, 13, 27, 49};
vector<int> a = original; insertionSort(a); cout << "直接插入排序: "; printArray(a);
a = original; shellSort(a); cout << "希尔排序: "; printArray(a);
a = original; bubbleSort(a); cout << "冒泡排序: "; printArray(a);
a = original; quickSort(a, 0, (int)a.size() - 1); cout << "快速排序: "; printArray(a);
a = original; selectionSort(a); cout << "简单选择排序: "; printArray(a);
a = original; heapSort(a); cout << "堆排序: "; printArray(a);
a = original; mergeSort(a, 0, (int)a.size() - 1); cout << "归并排序: "; printArray(a);
return 0;
}
public class SortDemo {
// 打印数组
static void printArray(int[] a) {
for (int x : a) System.out.print(x + " ");
System.out.println();
}
// 1. 直接插入排序(稳定)
static void insertionSort(int[] a) {
for (int i = 1; i < a.length; i++) {
int key = a[i], j = i - 1;
while (j >= 0 && a[j] > key) { a[j + 1] = a[j]; j--; }
a[j + 1] = key;
}
}
// 2. 希尔排序(不稳定)
static void shellSort(int[] a) {
for (int gap = a.length / 2; gap > 0; gap /= 2)
for (int i = gap; i < a.length; i++) {
int key = a[i], j = i;
while (j >= gap && a[j - gap] > key) { a[j] = a[j - gap]; j -= gap; }
a[j] = key;
}
}
// 3. 冒泡排序(稳定,带提前结束标志)
static void bubbleSort(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
boolean swapped = false;
for (int j = 0; j < a.length - 1 - i; j++)
if (a[j] > a[j + 1]) { int t = a[j]; a[j] = a[j + 1]; a[j + 1] = t; swapped = true; }
if (!swapped) break;
}
}
// 4. 快速排序(挖坑法,不稳定)
static int partition(int[] a, int lo, int hi) {
int pivot = a[lo]; // 挖坑
while (lo < hi) {
while (lo < hi && a[hi] >= pivot) hi--;
a[lo] = a[hi];
while (lo < hi && a[lo] <= pivot) lo++;
a[hi] = a[lo];
}
a[lo] = pivot;
return lo;
}
static void quickSort(int[] a, int lo, int hi) {
if (lo < hi) {
int p = partition(a, lo, hi);
quickSort(a, lo, p - 1);
quickSort(a, p + 1, hi);
}
}
// 5. 简单选择排序(不稳定)
static void selectionSort(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
int minIdx = i;
for (int j = i + 1; j < a.length; j++)
if (a[j] < a[minIdx]) minIdx = j;
if (minIdx != i) { int t = a[i]; a[i] = a[minIdx]; a[minIdx] = t; }
}
}
// 6. 堆排序(不稳定)
static void heapify(int[] a, int n, int i) {
int largest = i, l = 2 * i + 1, r = 2 * i + 2;
if (l < n && a[l] > a[largest]) largest = l;
if (r < n && a[r] > a[largest]) largest = r;
if (largest != i) { int t = a[i]; a[i] = a[largest]; a[largest] = t; heapify(a, n, largest); }
}
static void heapSort(int[] a) {
int n = a.length;
for (int i = n / 2 - 1; i >= 0; i--) heapify(a, n, i); // 建大根堆
for (int i = n - 1; i > 0; i--) { int t = a[0]; a[0] = a[i]; a[i] = t; heapify(a, i, 0); }
}
// 7. 二路归并排序(稳定)
static void merge(int[] a, int lo, int mid, int hi) {
int len = hi - lo + 1;
int[] tmp = new int[len];
int i = lo, j = mid + 1, k = 0;
while (i <= mid && j <= hi) tmp[k++] = (a[i] <= a[j]) ? a[i++] : a[j++];
while (i <= mid) tmp[k++] = a[i++];
while (j <= hi) tmp[k++] = a[j++];
for (int m = 0; m < len; m++) a[lo + m] = tmp[m];
}
static void mergeSort(int[] a, int lo, int hi) {
if (lo < hi) {
int mid = lo + (hi - lo) / 2;
mergeSort(a, lo, mid);
mergeSort(a, mid + 1, hi);
merge(a, lo, mid, hi);
}
}
public static void main(String[] args) {
int[] original = {49, 38, 65, 97, 76, 13, 27, 49};
int[] a = original.clone(); insertionSort(a); System.out.print("直接插入排序: "); printArray(a);
a = original.clone(); shellSort(a); System.out.print("希尔排序: "); printArray(a);
a = original.clone(); bubbleSort(a); System.out.print("冒泡排序: "); printArray(a);
a = original.clone(); quickSort(a, 0, a.length - 1); System.out.print("快速排序: "); printArray(a);
a = original.clone(); selectionSort(a); System.out.print("简单选择排序: "); printArray(a);
a = original.clone(); heapSort(a); System.out.print("堆排序: "); printArray(a);
a = original.clone(); mergeSort(a, 0, a.length - 1); System.out.print("归并排序: "); printArray(a);
}
}
# ---------- 7 种排序算法 ----------
def insertion_sort(a):
"""1. 直接插入排序(稳定)"""
for i in range(1, len(a)):
key = a[i]
j = i - 1
while j >= 0 and a[j] > key:
a[j + 1] = a[j]
j -= 1
a[j + 1] = key
def shell_sort(a):
"""2. 希尔排序(不稳定)"""
n = len(a)
gap = n // 2
while gap > 0:
for i in range(gap, n):
key = a[i]
j = i
while j >= gap and a[j - gap] > key:
a[j] = a[j - gap]
j -= gap
a[j] = key
gap //= 2
def bubble_sort(a):
"""3. 冒泡排序(稳定,带提前结束标志)"""
n = len(a)
for i in range(n - 1):
swapped = False
for j in range(n - 1 - i):
if a[j] > a[j + 1]:
a[j], a[j + 1] = a[j + 1], a[j]
swapped = True
if not swapped:
break
def _partition(a, lo, hi):
"""快速排序挖坑法分区"""
pivot = a[lo] # 挖坑
while lo < hi:
while lo < hi and a[hi] >= pivot:
hi -= 1
a[lo] = a[hi]
while lo < hi and a[lo] <= pivot:
lo += 1
a[hi] = a[lo]
a[lo] = pivot
return lo
def quick_sort(a, lo, hi):
"""4. 快速排序(不稳定)"""
if lo < hi:
p = _partition(a, lo, hi)
quick_sort(a, lo, p - 1)
quick_sort(a, p + 1, hi)
def selection_sort(a):
"""5. 简单选择排序(不稳定)"""
n = len(a)
for i in range(n - 1):
min_idx = i
for j in range(i + 1, n):
if a[j] < a[min_idx]:
min_idx = j
if min_idx != i:
a[i], a[min_idx] = a[min_idx], a[i]
def _heapify(a, n, i):
"""堆排序:对以 i 为根的子树调整为大根堆"""
largest = i
l, r = 2 * i + 1, 2 * i + 2
if l < n and a[l] > a[largest]:
largest = l
if r < n and a[r] > a[largest]:
largest = r
if largest != i:
a[i], a[largest] = a[largest], a[i]
_heapify(a, n, largest)
def heap_sort(a):
"""6. 堆排序(不稳定)"""
n = len(a)
for i in range(n // 2 - 1, -1, -1):
_heapify(a, n, i) # 建大根堆
for i in range(n - 1, 0, -1):
a[0], a[i] = a[i], a[0]
_heapify(a, i, 0)
def _merge(a, lo, mid, hi):
"""归并排序:合并两个有序区间 [lo,mid] 与 [mid+1,hi]"""
tmp = []
i, j = lo, mid + 1
while i <= mid and j <= hi:
if a[i] <= a[j]:
tmp.append(a[i]); i += 1
else:
tmp.append(a[j]); j += 1
while i <= mid:
tmp.append(a[i]); i += 1
while j <= hi:
tmp.append(a[j]); j += 1
a[lo:hi + 1] = tmp
def merge_sort(a, lo, hi):
"""7. 二路归并排序(稳定)"""
if lo < hi:
mid = lo + (hi - lo) // 2
merge_sort(a, lo, mid)
merge_sort(a, mid + 1, hi)
_merge(a, lo, mid, hi)
if __name__ == "__main__":
original = [49, 38, 65, 97, 76, 13, 27, 49]
a = original[:]; insertion_sort(a); print("直接插入排序:", a)
a = original[:]; shell_sort(a); print("希尔排序: ", a)
a = original[:]; bubble_sort(a); print("冒泡排序: ", a)
a = original[:]; quick_sort(a, 0, len(a) - 1); print("快速排序: ", a)
a = original[:]; selection_sort(a); print("简单选择排序:", a)
a = original[:]; heap_sort(a); print("堆排序: ", a)
a = original[:]; merge_sort(a, 0, len(a) - 1); print("归并排序: ", a)