1.插入排序(扑克排序)
java
复制代码
public static void insertionSort(int[] array) {
// 外层循环:遍历未排序部分(从第二个元素开始)
for (int i = 1; i < array.length; i++) {
int current = array[i]; // 当前待插入元素
int j = i - 1; // 已排序部分的最后一个索引
// 内层循环:从后向前扫描已排序部分
// 若当前元素更小,则将元素向右移动
while (j >= 0 && array[j] > current) {
array[j + 1] = array[j]; // 元素右移
j--;
}
// 将当前元素插入正确位置
array[j + 1] = current;
}
}
2. 希尔排序
java
复制代码
public static void shellSort(int[] array) {
if (array == null || array.length <= 1) return;
// 初始化增量为数组长度的一半[3,4](@ref)
int gap = array.length / 2;
while (gap > 0) {
// 对每个增量间隔的子序列进行插入排序[2,5](@ref)
for (int i = gap; i < array.length; i++) {
int temp = array[i]; // 当前待插入元素
int j = i - gap; // 前一个元素的索引
// 插入排序逻辑:比当前元素大的都向后移动
while (j >= 0 && array[j] > temp) {
array[j + gap] = array[j];
j -= gap;
}
array[j + gap] = temp; // 插入到正确位置
}
gap /= 2; // 缩小增量[3,6](@ref)
}
}
3. 直接选择
java
复制代码
public static void selectionSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i;
// 寻找[i, n)区间内的最小值索引
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// 仅当找到更小值时交换(减少不必要的交换)
if (minIndex != i) {
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
}
4. 堆排序
java
复制代码
/**
* 堆排序入口方法
* @param arr 待排序数组
*/
public static void heapSort(int[] arr) {
if (arr == null || arr.length <= 1) return;
// 1. 构建最大堆(时间复杂度O(n))[1,6](@ref)
int n = arr.length;
for (int i = n/2 - 1; i >= 0; i--) { // 从最后一个非叶子节点开始
heapify(arr, n, i);
}
// 2. 逐个提取堆顶元素(时间复杂度O(n logn))[3,8](@ref)
for (int i = n-1; i > 0; i--) {
// 交换堆顶与当前末尾元素
swap(arr, 0, i);
// 调整剩余元素维持堆性质
heapify(arr, i, 0);
}
}
/**
* 堆化操作(向下调整)
* @param arr 待调整数组
* @param n 堆的有效长度
* @param i 当前调整的节点索引
*/
private static void heapify(int[] arr, int n, int i) {
int largest = i; // 初始化最大值为当前节点
int left = 2*i + 1; // 左子节点索引
int right = 2*i + 2; // 右子节点索引
// 找出当前节点与子节点的最大值[1,6](@ref)
if (left < n && arr[left] > arr[largest]) {
largest = left;
}
if (right < n && arr[right] > arr[largest]) {
largest = right;
}
// 若最大值不是当前节点,需要交换并递归调整[8](@ref)
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;
}
5. 冒泡排序
java
复制代码
/**
* 冒泡排序优化版(带提前终止机制)
* @param arr 待排序数组
*/
public static void bubbleSort(int[] arr) {
if (arr == null || arr.length <= 1) return;
int n = arr.length;
// 外层循环控制排序轮次
for (int i = 0; i < n - 1; i++) {
boolean swapped = false; // 优化点:标记是否发生交换[4](@ref)
// 内层循环执行相邻元素比较(每轮减少i个已排序元素)
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
// 交换相邻元素
swap(arr, j, j + 1);
swapped = true;
}
}
// 若本轮未交换则提前终止[4](@ref)
if (!swapped) break;
}
}
/**
* 元素交换方法
* @param arr 数组
* @param i 索引1
* @param j 索引2
*/
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
6. 快速排序
java
复制代码
/**
* 快速排序核心方法(双指针优化版)
* @param arr 待排序数组
* @param low 左边界索引
* @param high 右边界索引
*/
public static void quickSort(int[] arr, int low, int high) {
if (low >= high) return; // 递归终止条件[2,5](@ref)
int pivot = partition(arr, low, high); // 执行分区操作
quickSort(arr, low, pivot - 1); // 递归处理左子数组
quickSort(arr, pivot + 1, high); // 递归处理右子数组
}
/**
* 分区操作(原地交换版本)
* @return 基准值的最终位置
*/
private static int partition(int[] arr, int low, int high) {
int pivot = arr[low]; // 基准值选择优化(此处简化为取首元素)[2](@ref)
int left = low, right = high;
while (left < right) {
// 从右向左找第一个小于基准的元素[5](@ref)
while (left < right && arr[right] >= pivot) right--;
// 从左向右找第一个大于基准的元素[5](@ref)
while (left < right && arr[left] <= pivot) left++;
if (left < right) swap(arr, left, right); // 交换不符合条件的元素
}
swap(arr, low, left); // 将基准值放到正确位置[5](@ref)
return left;
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
7. 归并排序
java
复制代码
/**
* 归并排序入口方法
* @param arr 待排序数组
*/
public static void mergeSort(int[] arr) {
if (arr == null || arr.length <= 1) return;
int[] temp = new int[arr.length]; // 创建临时数组避免递归中频繁开辟空间[6,7](@ref)
sort(arr, 0, arr.length - 1, temp);
}
/**
* 递归分治与合并
* @param arr 原数组
* @param left 左边界索引
* @param right 右边界索引
* @param temp 临时数组
*/
private static void sort(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = left + (right - left) / 2; // 防溢出写法[6](@ref)
// 分治递归(类似二叉树后序遍历)
sort(arr, left, mid, temp); // 处理左半区间[4,7](@ref)
sort(arr, mid + 1, right, temp); // 处理右半区间[4,7](@ref)
// 合并已排序的子数组
merge(arr, left, mid, right, temp); // 核心合并逻辑[6,10](@ref)
}
}
/**
* 合并两个有序子数组
* @param left 左子数组起始索引
* @param mid 中间分隔索引
* @param right 右子数组结束索引
*/
private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int i = left; // 左子数组指针
int j = mid + 1; // 右子数组指针
int t = 0; // 临时数组指针
// 比较填充临时数组
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) { // 保持稳定性(相等时左子数组优先)[10](@ref)
temp[t++] = arr[i++];
} else {
temp[t++] = arr[j++];
}
}
// 处理剩余元素
while (i <= mid) temp[t++] = arr[i++]; // 左子数组剩余元素[7](@ref)
while (j <= right) temp[t++] = arr[j++]; // 右子数组剩余元素[7](@ref)
// 将临时数组数据拷贝回原数组
t = 0;
while (left <= right) {
arr[left++] = temp[t++]; // 原地更新原数组[6,8](@ref)
}
}
8. 基数排序
java
复制代码
/**
* 基数排序核心方法(LSD优化版)
* @param arr 待排序数组(仅支持非负整数)
*/
public static void radixSort(int[] arr) {
if (arr == null || arr.length <= 1) return;
// 1. 获取最大值确定最大位数[4,6](@ref)
int max = Arrays.stream(arr).max().getAsInt();
int exp = 1; // 当前排序位数(1表示个位)
// 2. 从低位到高位循环处理每个数字位[1,6](@ref)
while (max / exp > 0) {
countingSortByDigit(arr, exp);
exp *= 10; // 升到更高位:个位→十位→百位...
}
}
/**
* 按指定位数进行计数排序(稳定版)
* @param exp 当前处理位数的权值(例如个位=1,十位=10)
*/
private static void countingSortByDigit(int[] arr, int exp) {
int n = arr.length;
int[] output = new int[n]; // 临时输出数组
int[] count = new int[10]; // 0-9的计数器[6](@ref)
// 统计当前位各数字出现次数[5](@ref)
for (int num : arr) {
int digit = (num / exp) % 10;
count[digit]++;
}
// 计算前缀和确定元素最终位置[5,6](@ref)
for (int i = 1; i < 10; i++) {
count[i] += count[i-1];
}
// 逆序填充保证稳定性[5,6](@ref)
for (int i = n-1; i >= 0; i--) {
int digit = (arr[i] / exp) % 10;
output[--count[digit]] = arr[i];
}
// 将排序结果写回原数组[6](@ref)
System.arraycopy(output, 0, arr, 0, n);
Arrays.fill(count, 0); // 重置计数器
}