/**
* 常见排序算法汇总
*/
public class SortAlgorithms {
/**
* 1️⃣ 冒泡排序(Bubble Sort)
* 思想:相邻元素两两比较,大的往后沉。
* 时间复杂度:O(n^2)
* 稳定性:稳定
*/
public static void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
// 若前一个数比后一个大,则交换
if (arr[j] > arr[j + 1]) {
swap(arr, j, j + 1);
}
}
}
}
/**
* 2️⃣ 选择排序(Selection Sort)
* 思想:每轮选择最小(或最大)的元素放到前面。
* 时间复杂度:O(n^2)
* 稳定性:不稳定
*/
public static void selectionSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i;
// 找到未排序部分的最小值
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// 将最小值放到当前轮的开头
swap(arr, i, minIndex);
}
}
/**
* 3️⃣ 插入排序(Insertion Sort)
* 思想:将元素插入到前面已排序部分的正确位置。
* 时间复杂度:O(n^2)
* 稳定性:稳定
*/
public static void insertionSort(int[] arr) {
for (int i = 1; i < arr.length; 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; // 插入
}
}
/**
* 4️⃣ 希尔排序(Shell Sort)
* 思想:将序列分为若干子序列进行插入排序,逐步减小间隔。
* 时间复杂度:O(n log n)
* 稳定性:不稳定
*/
public static void shellSort(int[] arr) {
// gap为步长,每轮缩小一半
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < arr.length; i++) {
int temp = arr[i];
int j = i;
// 按gap间隔进行插入排序
while (j >= gap && arr[j - gap] > temp) {
arr[j] = arr[j - gap];
j -= gap;
}
arr[j] = temp;
}
}
}
/**
* 5️⃣ 归并排序(Merge Sort)
* 思想:分治法,将数组分为两半,分别排序后再合并。
* 时间复杂度:O(n log n)
* 稳定性:稳定
*/
public static void mergeSort(int[] arr) {
mergeSortHelper(arr, 0, arr.length - 1);
}
private static void mergeSortHelper(int[] arr, int left, int right) {
if (left >= right) return; // 递归终止条件
int mid = (left + right) / 2;
mergeSortHelper(arr, left, mid); // 排序左半部分
mergeSortHelper(arr, mid + 1, right); // 排序右半部分
merge(arr, left, mid, right); // 合并
}
// 合并两个有序子数组
private static void merge(int[] arr, int left, int mid, int right) {
int[] temp = new int[right - left + 1];
int i = left, j = mid + 1, k = 0;
// 合并过程:按顺序比较左右两边元素
while (i <= mid && j <= right) {
temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
}
// 将剩余元素依次拷贝
while (i <= mid) temp[k++] = arr[i++];
while (j <= right) temp[k++] = arr[j++];
// 拷贝回原数组
for (int t = 0; t < temp.length; t++) {
arr[left + t] = temp[t];
}
}
/**
* 6️⃣ 快速排序(Quick Sort)
* 思想:分治法,选取一个“基准”,小的放左边,大的放右边。
* 时间复杂度:平均O(n log n),最坏O(n^2)
* 稳定性:不稳定
*/
public static void quickSort(int[] arr) {
quickSortHelper(arr, 0, arr.length - 1);
}
private static void quickSortHelper(int[] arr, int left, int right) {
if (left >= right) return;
int pivot = arr[left]; // 选取第一个元素为基准
int i = left, j = right;
// 分区过程
while (i < j) {
while (i < j && arr[j] >= pivot) j--; // 从右往左找小于pivot的数
while (i < j && arr[i] <= pivot) i++; // 从左往右找大于pivot的数
if (i < j) swap(arr, i, j);
}
// 将基准放到正确位置
swap(arr, left, i);
// 递归左右子序列
quickSortHelper(arr, left, i - 1);
quickSortHelper(arr, i + 1, right);
}
/**
* 7️⃣ 堆排序(Heap Sort)
* 思想:利用堆结构(最大堆)来排序。
* 时间复杂度:O(n log n)
* 稳定性:不稳定
*/
public static void heapSort(int[] arr) {
int n = arr.length;
// 1. 构建最大堆(从最后一个非叶子节点开始)
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(arr, n, i);
}
// 2. 取出堆顶元素放到数组末尾
for (int i = n - 1; i > 0; i--) {
swap(arr, 0, i); // 交换堆顶与末尾元素
heapify(arr, i, 0); // 重新调整堆
}
}
// 调整堆,使其满足最大堆性质
private static void heapify(int[] arr, int n, int i) {
int largest = i; // 假设当前节点最大
int left = 2 * i + 1; // 左子节点
int right = 2 * i + 2; // 右子节点
// 找出最大值的节点
if (left < n && arr[left] > arr[largest]) largest = left;
if (right < n && arr[right] > arr[largest]) largest = right;
// 如果最大值不是当前节点,则交换并递归调整
if (largest != i) {
swap(arr, i, largest);
heapify(arr, n, largest);
}
}
/**
* 工具函数:交换数组中的两个元素
*/
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
/**
* 🧪 测试主函数
*/
public static void main(String[] args) {
int[] arr = {5, 3, 8, 4, 2, 7, 1, 6};
System.out.println("原始数组:");
printArray(arr);
// 测试不同排序算法
quickSort(arr); // 可替换为 bubbleSort(arr)、mergeSort(arr) 等
System.out.println("排序后:");
printArray(arr);
}
/**
* 辅助打印函数
*/
public static void printArray(int[] arr) {
for (int n : arr) {
System.out.print(n + " ");
}
System.out.println();
}
}
| 算法 |
平均复杂度 |
最好 |
最坏 |
稳定性 |
特点 |
| 冒泡排序 |
O(n²) |
O(n) |
O(n²) |
✅ 稳定 |
简单易理解 |
| 选择排序 |
O(n²) |
O(n²) |
O(n²) |
❌ 不稳定 |
少交换但慢 |
| 插入排序 |
O(n²) |
O(n) |
O(n²) |
✅ 稳定 |
适合基本有序 |
| 希尔排序 |
O(n log n) |
- |
- |
❌ 不稳定 |
改进插入排序 |
| 归并排序 |
O(n log n) |
O(n log n) |
O(n log n) |
✅ 稳定 |
占用额外内存 |
| 快速排序 |
O(n log n) |
O(n log n) |
O(n²) |
❌ 不稳定 |
实际中最快之一 |
| 堆排序 |
O(n log n) |
O(n log n) |
O(n log n) |
❌ 不稳定 |
适合大数据排序 |