Java 三路快排

三路快速排序(3-Way QuickSort )是快速排序的优化版本,特别适用于处理包含大量重复元素的数组 。其核心思想是将数组划分为三个区域:小于基准值 、等于基准值 和大于基准值,从而减少不必要的递归和交换

三路快排原理

  1. 分区逻辑:

    • 使用三个指针 lt(less than)、current(当前遍历位置)、gt(greater than)将数组划分为三部分:

      • [low, lt-1]:小于基准值的元素

      • [lt, gt]:等于基准值的元素

      • [gt+1, high]:大于基准值的元素

    • 通过一次遍历,将元素分配到正确区域。

  2. 时间复杂度:

    • 平均 :O(n log n)

    • 最坏 (大量重复元素时):O(n)(优于传统快排的 O(n²))

Java 实现代码

java 复制代码
public class ThreeWayQuickSort {

    public static void sort(int[] arr) {
        if (arr == null || arr.length <= 1) return;
        threeWayQuickSort(arr, 0, arr.length - 1);
    }

    private static void threeWayQuickSort(int[] arr, int low, int high) {
        if (low >= high) return;

        // 选择基准值(这里选第一个元素)
        int pivot = arr[low];
        int lt = low;      // 小于 pivot 的右边界
        int gt = high;     // 大于 pivot 的左边界
        int current = low; // 当前遍历指针

        while (current <= gt) {
            if (arr[current] < pivot) {
                swap(arr, lt, current);
                lt++;
                current++;
            } else if (arr[current] > pivot) {
                swap(arr, current, gt);
                gt--;
            } else {
                current++;
            }
        }

        // 递归处理小于和大于区域
        threeWayQuickSort(arr, low, lt - 1);
        threeWayQuickSort(arr, gt + 1, high);
    }

    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 = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
        sort(arr);
        System.out.println(Arrays.toString(arr)); 
        // 输出: [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]
    }
}

关键步骤解析

  1. 初始化指针:

    • lt 指向数组起始位置(low),gt 指向数组末尾(high),current 从 low 开始遍历。
  2. 遍历与交换:

    • 如果 arr[current] < pivot:将 current 与 lt 处的元素交换,lt 和 current 均右移。

    • 如果 arr[current] > pivot:将 current 与 gt 处的元素交换,gt 左移(current 不移动,因为交换后的新元素需要再次检查)。

    • 如果 arr[current] == pivot:直接移动 current 指针。

  3. 递归处理子数组:

    • 对 [low, lt-1](小于区域)和 [gt+1, high](大于区域)递归排序,中间区域 [lt, gt] 已经有序。

示例流程

假设初始数组为 [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5],基准值 pivot=3:

  1. 第一次分区后:

    • 小于区域:[1, 1, 2]

    • 等于区域:[3, 3]

    • 大于区域:[4, 5, 9, 6, 5, 5]

  2. 递归排序小于区域 [1, 1, 2] 和大于区域 [4, 5, 9, 6, 5, 5]。


优势与适用场景

  • 优势:

    • 高效处理重复元素,避免传统快排的重复递归。

    • 减少元素交换次数。

  • 适用场景:

    • 数组中存在大量重复元素(如日志数据、用户行为数据)。

    • 需要稳定排序但允许非稳定实现的情况。

相关推荐
学长毕设23 分钟前
基于springboot科创竞赛信息平台-附源码
java·spring boot·后端
聪明的笨猪猪1 小时前
Java 工程案例:AI 生成 @Async 异步线程池踩坑
java·经验分享·面试·ai编程
学长毕设1 小时前
基于SpringBoot公务员考试交流平台-附源码
java·spring boot·后端
SL_staff4 小时前
私有化低代码:面向强监管行业的可控数字化实践
java·低代码
三翼鸟数字化技术团队4 小时前
高性能存储引擎RocksDB:原理与Java生态实践
java
SL_staff4 小时前
JVS-APS有限产能建模的七个刚性支点:面向产线真实约束的技术实现解析
java·开源·全栈
特立独行的猫A5 小时前
少 3 个环节、少 1 次 ABI、少 3500 行代码:cj-tauri 与 Ionic/Capacitor 的鸿蒙桥接机制对比
java·后端·python
学长毕设5 小时前
基于SpringBoot的高校后勤报修管理系统-附源码
java·spring boot·后端
特立独行的猫A5 小时前
cj-tauri vs Rust/Tauri 同款播放器实测:编译 21 秒 vs 11 分钟,磁盘 12 MB vs 1.2 GB
java·后端·python
杨凯凡5 小时前
Spring AI RAG 实战:向量检索、租户过滤、引用溯源与防幻觉边界
java·人工智能·spring