【常见排序算法】java 代码实现

发布于:2025-06-14 ⋅ 阅读:(18) ⋅ 点赞:(0)
排序算法 时间复杂度 空间复杂度 稳定性 排序策略 递归性 适应性
直接插入排序 O(n²) O(1) 稳定 插入类 非递归 自适应
二分插入排序 O(n²) O(1) 稳定 插入类 非递归 自适应
希尔排序 O(n^1.3)~O(n²) O(1) 不稳定 插入类 非递归 部分自适应
冒泡排序 O(n²) O(1) 稳定 交换类 非递归 自适应
快速排序 O(n log n) O(log n) 不稳定 交换类 递归 非自适应
归并排序 O(n log n) O(n) 稳定 归并类 递归 非自适应

直插排序

public static void straight_insert_sort(int[] r, int n) {
    // 直接插入排序:将未排序元素逐个插入到已排序序列的适当位置
    // 假设数组索引从1开始,r[0]作为哨兵,不参与排序
    
    int i, j;
    
    // 从第2个元素开始,逐个插入到前面已排序部分
    for (i = 2; i <= n; i++) {
        r[0] = r[i];  // 将当前待插入元素暂存到哨兵位置
        j = i - 1;    // 已排序部分的最后一个元素
        
        // 从后向前查找插入位置,同时移动元素
        while (r[0] < r[j]) {
            r[j + 1] = r[j];  // 元素后移一位
            j--;              // 继续向前比较
        }
        
        // 找到插入位置,将暂存的元素插入
        r[j + 1] = r[0];
    }
}

二分插入排序

public static void binary_insert_sort(int[] r) {
    // 二分插入排序:结合二分查找优化的插入排序
    // 假设数组索引从1开始,r[0]作为哨兵,不参与排序
    
    int i, j, low, high, mid;
    
    // 从第2个元素开始,逐个插入到前面已排序部分
    for (i = 2; i < r.length; i++) {
        r[0] = r[i];  // 将当前待插入元素暂存到哨兵位置
        low = 1;      // 已排序部分的起始位置
        high = i - 1; // 已排序部分的结束位置
        
        // 二分查找插入位置
        while (low <= high) {
            mid = (low + high) / 2;  // 计算中间位置
            
            if (r[0] < r[mid]) {     // 插入位置在左半部分
                high = mid - 1;
            } else {                 // 插入位置在右半部分
                low = mid + 1;
            }
        }
        
        // 找到插入位置后,将元素后移
        for (j = i - 1; j >= high + 1; j--) {
            r[j + 1] = r[j];  // 元素后移一位
        }
        
        // 在找到的位置插入元素
        r[high + 1] = r[0];
    }
}

希尔排序

public static void shell_sort(int[] r) {
    // 希尔排序:基于插入排序的改进算法
    // 通过设置不同的间隔(d),将数组分成多个子序列进行排序
    // 随着间隔逐渐减小,数组逐渐接近有序,最终间隔为1时完成排序
    
    int d, i, j;
    
    // 初始间隔为数组长度的一半,然后每次减半
    for (d = r.length / 2; d >= 1; d = d / 2) {
        
        // 对每个子序列进行插入排序
        for (i = d + 1; i < r.length; i++) {
            r[0] = r[i];  // 暂存当前元素
            j = i - d;    // 子序列的前一个元素
            
            // 在子序列中向前查找插入位置
            while (j > 0 && r[0] < r[j]) {
                r[j + d] = r[j];  // 元素后移d个位置
                j = j - d;        // 继续向前查找
            }
            
            // 插入元素
            r[j + d] = r[0];
        }
    }
}

冒泡排序

public static void bubbleSort(int[] r, int n) {
    int exchange, bound;
    // exchange: 记录最后一次交换的位置
    // bound: 每轮比较的右边界
    
    exchange = n;  // 初始时,整个数组都需要排序
    while (exchange != 0) {  // 只要还有交换发生,就继续排序
        bound = exchange;  // 上一轮最后一次交换的位置,作为本轮的右边界
        exchange = 0;  // 重置交换位置,准备记录本轮的最后一次交换
        
        for (int j = 1; j < bound; j++) {  // 只需要比较到上一轮最后交换的位置
            if (r[j] > r[j + 1]) {  // 如果前一个元素比后一个大,就交换
                r[0] = r[j];  // 交换元素
                r[j] = r[j + 1];
                r[j + 1] = r[0];
                exchange = j;  // 记录最后一次交换的位置
            }
        }
        // 循环结束后,bound之后的元素已经有序,下一轮只需比较到bound位置
    }
}

快速排序

public static void quickSort(int[] r, int first, int end) {
    // 快速排序的递归实现
    // 参数:
    //   r: 待排序数组
    //   first: 当前子数组的起始索引
    //   end: 当前子数组的结束索引
    
    if (first < end) {  // 递归终止条件:子数组长度大于1
        // 分区操作:将数组分为两部分
        // 左边部分 <= 基准,右边部分 >= 基准
        // pivot 是基准元素最终所在的位置
        int pivot = partition(r, first, end);
        
        // 递归排序左半部分
        quickSort(r, first, pivot - 1);
        
        // 递归排序右半部分
        quickSort(r, pivot + 1, end);
    }
    // 当 first >= end 时,子数组长度为0或1,已经有序,直接返回
}

public static int partition(int[] r, int first, int end) {
    // 以第一个元素为基准,将数组分为两部分
    // 左边部分 <= 基准,右边部分 >= 基准
    // 返回基准元素最终所在的位置
    
    int i = first, j = end, temp;  // i: 左指针,j: 右指针
    
    while (i < j) {  // 当左右指针未相遇时,继续分区
        // 从右向左找第一个小于基准的元素
        while (i < j && r[i] <= r[j]) j--;
        
        if (i < j) {  // 如果找到,交换左右指针所指元素
            temp = r[i];
            r[i] = r[j];
            r[j] = temp;
            i++;  // 左指针右移
        }
        
        // 从左向右找第一个大于基准的元素
        while (i < j && r[i] <= r[j]) i++;
        
        if (i < j) {  // 如果找到,交换左右指针所指元素
            temp = r[i];
            r[i] = r[j];
            r[j] = temp;
            j--;  // 右指针左移
        }
    }
    
    // 当i=j时,分区完成,返回基准元素的位置
    return i;
}

归并排序

public static void mergesort(int[] r, int s, int t) {
    // 参数:
    //   r: 待排序数组
    //   s: 当前子数组的起始索引
    //   t: 当前子数组的结束索引
    
    int i, m;
    
    // 递归终止条件:当子数组只有一个元素时,直接返回
    if (s == t) return;
    
    // 计算中间位置,将数组分成两部分
    m = (s + t) / 2;
    
    // 递归排序左半部分
    mergesort(r, s, m);
    
    // 递归排序右半部分
    mergesort(r, m + 1, t);
    
    // 合并已排序的两部分
    merge(r, s, m, t);
}


public static void merge(int[] r, int s, int m, int t) {
    // 参数:
    //   r: 待合并数组
    //   s: 左子数组的起始索引
    //   m: 左子数组的结束索引(也是中间位置)
    //   t: 右子数组的结束索引
    
    // 创建辅助数组,用于临时存储合并结果
    int[] r1 = new int[t + 1];
    
    // i: 左子数组的当前索引
    // j: 右子数组的当前索引
    // k: 辅助数组的当前索引
    int i = s, j = m + 1, k = s;
    
    // 同时遍历左右子数组,将较小的元素放入辅助数组
    while (i <= m && j <= t) {
        if (r[i] <= r[j]) {
            r1[k++] = r[i++];  // 左子数组元素较小,放入辅助数组
        } else {
            r1[k++] = r[j++];  // 右子数组元素较小,放入辅助数组
        }
    }
    
    // 处理左子数组剩余元素
    while (i <= m) {
        r1[k++] = r[i++];
    }
    
    // 处理右子数组剩余元素
    while (j <= t) {
        r1[k++] = r[j++];
    }
    
    // 将辅助数组中的元素复制回原数组
    for (i = s; i <= t; i++) {
        r[i] = r1[i];
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到