排序(3)-第三篇:交换排序专题——从冒泡排序到快速排序的效率飞跃

📌 引言

交换排序,顾名思义,核心操作就是通过"两两比较并交换"来达到有序的目的 。这一族群里有两个极具代表性的选手:一个是无数人的启蒙算法------冒泡排序 ;另一个则是工业界、面试官长盛不衰的宠儿------快速排序。它们之间,是一场关于执行效率的惊艳飞跃。

1. 冒泡排序(Bubble Sort)

💡 核心思想

从左到开依次比较相邻的两个数,如果前面的数比后面的大,就交换它们。这样一轮下来,当前区间的最大值就像"气泡"一样浮到了数组的最右端。

💻 Java 代码实现(带提前跳出优化)
复制代码
public class BubbleSort {
    public static void sort(int[] arr) {
        if (arr == null || arr.length < 2) return;
        int n = arr.length;
        
        for (int i = 0; i < n - 1; i++) {
            boolean swapped = false; // 优化:若某一趟没有发生任何交换,说明已经有序了
            for (int j = 0; j < n - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    swapped = true;
                }
            }
            if (!swapped) break; 
        }
    }
}

2. 快速排序(Quick Sort)

🚀 为什么叫快速排序?

冒泡排序太慢了,因为每次交换只能解决相邻 两个元素的无序问题。而快速排序采用分治思想(Divide and Conquer),通过选择一个"基准值",让大小元素横跨大半个数组进行对调,从而实现大步流星的排序。

💡 核心思想
  1. 找基准(Pivot): 通常选区间第一个数作为基准。

  2. 分区(Partition): 通过双指针左右开弓,把比 Pivot 小的扔到左边,比 Pivot 大的扔到右边。

  3. 递归(Solve): 此时 Pivot 已经锁定了它的最终位置。接下来对左、右两部分分别重复上述过程。

💻 Java 代码实现(标准双指针法)
复制代码
public class QuickSort {
    public static void sort(int[] arr) {
        if (arr == null || arr.length < 2) return;
        quickSort(arr, 0, arr.length - 1);
    }

    private static void quickSort(int[] arr, int low, int high) {
        if (low >= high) return;
        
        // 核心切分操作,返回基准值的最终正确索引
        int pivotIndex = partition(arr, low, high);
        
        quickSort(arr, low, pivotIndex - 1);  // 递归搞定左半部分
        quickSort(arr, pivotIndex + 1, high); // 递归搞定右半部分
    }

    private static int partition(int[] arr, int low, int high) {
        int pivot = arr[low]; 
        int i = low, j = high + 1;
        
        while (true) {
            // 左指针向右找第一个比 pivot 大的数
            while (arr[++i] < pivot) if (i == high) break;
            // 右指针向左找第一个比 pivot 小的数
            while (pivot < arr[--j]) if (j == low) break;
            
            if (i >= j) break; // 指针相遇,退出循环
            swap(arr, i, j);   // 交换这两个错位的数
        }
        swap(arr, low, j); // 将基准值交换到它的最终正确位置 `j`
        return j; 
    }

    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

📊 交换排序大比拼

算法 最好时间复杂度 最坏时间复杂度 平均时间复杂度 空间复杂度 稳定性
冒泡排序 O(n) O(n^2) O(n^2) O(1) 稳定
快速排序 O(n \log n) O(n^2) O(n \log n) O(\log n) (递归栈) 不稳定
相关推荐
搬石头的马农1 小时前
御三家旗舰模型混战下的企业选型策略:GPT-5.6、Fable 5、Gemini 3.5 Pro 怎么选? - 微元算力(weytoken)
java·人工智能·python·gpt·ai编程
ywl4708120871 小时前
数据结构之链表反转算法
数据结构·算法·链表
牧子川1 小时前
019-JSON-Schema-自动生成
算法·大模型·格式化输出·tools
摇滚侠1 小时前
SpringMVC 入门到实战 域对象共享数据 33-43
java·后端·spring·intellij-idea
码语智行1 小时前
GDB 文件导入流程分析
java
jjjava2.01 小时前
软件测试与开发全流程解析
java·功能测试·测试用例
lhjcsubupt1 小时前
第二十二篇 从随机过程到IMU噪声模型
算法·机器学习·概率论
CodeStats1 小时前
JavaWeb 造轮者视角:Spring Boot 启动核心思想与完整链路解析
java·spring boot·后端
weixin_523185321 小时前
Spring事务为什么会失效?常见场景与解决方案总结
java·数据库·spring