【java实现+4种变体完整例子】排序算法中【快速排序】的详细解析,包含基础实现、常见变体的完整代码示例,以及各变体的对比表格

以下是快速排序的详细解析,包含基础实现、常见变体的完整代码示例,以及各变体的对比表格:


一、快速排序基础实现

原理

通过分治法选择一个基准元素(pivot),将数组分为两部分:

  • 左边元素均小于基准,
  • 右边元素均大于基准,
    然后递归排序子数组。
代码示例
java 复制代码
public class QuickSort {
    void sort(int[] arr, int low, int high) {
        if (low < high) {
            int pi = partition(arr, low, high); // 分区操作
            sort(arr, low, pi - 1); // 递归排序左半部分
            sort(arr, pi + 1, high); // 递归排序右半部分
        }
    }

    private int partition(int[] arr, int low, int high) {
        int pivot = arr[high]; // 选择最后一个元素作为基准
        int i = low - 1; // 小于基准的元素的索引
        for (int j = low; j < high; j++) {
            if (arr[j] <= pivot) {
                i++;
                swap(arr, i, j); // 将小于等于基准的元素移到左边
            }
        }
        swap(arr, i + 1, high); // 将基准放到正确位置
        return i + 1;
    }

    private void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}
复杂度分析
  • 时间复杂度
    • 最坏:O(n²)(如数组已有序,基准选择不当)。
    • 平均:O(n log n)
    • 最好:O(n log n)
  • 空间复杂度O(log n)(递归栈空间)。
  • 稳定性:不稳定(相同值的元素可能因交换顺序改变相对位置)。

二、常见变体及代码示例

1. 三向切分快速排序(处理重复元素)

改进点 :将数组分为三部分:小于、等于、大于基准的区域,适合处理大量重复元素。
适用场景:数据中有大量重复值(如荷兰国旗问题)。

java 复制代码
public class ThreeWayQuickSort {
    void sort(int[] arr, int low, int high) {
        if (low < high) {
            int[] partitionIndices = partition(arr, low, high);
            sort(arr, low, partitionIndices[0] - 1); // 左半部分(小于基准)
            sort(arr, partitionIndices[1] + 1, high); // 右半部分(大于基准)
        }
    }

    private int[] partition(int[] arr, int low, int high) {
        int pivot = arr[high];
        int less = low; // 小于基准的区域末尾
        int great = low; // 等于基准的区域末尾
        for (int i = low; i < high; i++) {
            if (arr[i] < pivot) {
                swap(arr, i, less);
                less++;
                swap(arr, i, great); // 将小于的元素移到最前
                great++;
            } else if (arr[i] == pivot) {
                swap(arr, i, great);
                great++;
            }
        }
        swap(arr, great, high); // 将基准放到中间区域
        return new int[]{less, great};
    }

    private void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}
2. 随机化快速排序

改进点 :随机选择基准,避免最坏情况(如输入已排序)。
适用场景:需要降低最坏时间复杂度的概率。

java 复制代码
import java.util.Random;

public class RandomizedQuickSort {
    void sort(int[] arr, int low, int high) {
        if (low < high) {
            int pi = randomizedPartition(arr, low, high);
            sort(arr, low, pi - 1);
            sort(arr, pi + 1, high);
        }
    }

    private int randomizedPartition(int[] arr, int low, int high) {
        Random rand = new Random();
        int pivotIndex = low + rand.nextInt(high - low + 1);
        swap(arr, pivotIndex, high); // 将随机选择的基准放到末尾
        return partition(arr, low, high);
    }

    private int partition(int[] arr, int low, int high) {
        int pivot = arr[high];
        int i = low - 1;
        for (int j = low; j < high; j++) {
            if (arr[j] <= pivot) {
                i++;
                swap(arr, i, j);
            }
        }
        swap(arr, i + 1, high);
        return i + 1;
    }

    private void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}
3. 迭代实现(非递归)

改进点 :用栈或队列模拟递归,避免栈溢出风险。
适用场景:大数组或递归深度受限的场景。

java 复制代码
public class IterativeQuickSort {
    void sort(int[] arr) {
        int n = arr.length;
        int low = 0;
        int high = n - 1;
        Stack<int[]> stack = new Stack<>();
        stack.push(new int[]{low, high});

        while (!stack.isEmpty()) {
            int[] range = stack.pop();
            int partitionIndex = partition(arr, range[0], range[1]);
            if (partitionIndex - 1 > range[0]) {
                stack.push(new int[]{range[0], partitionIndex - 1});
            }
            if (partitionIndex + 1 < range[1]) {
                stack.push(new int[]{partitionIndex + 1, range[1]});
            }
        }
    }

    private int partition(int[] arr, int low, int high) {
        int pivot = arr[high];
        int i = low - 1;
        for (int j = low; j < high; j++) {
            if (arr[j] <= pivot) {
                i++;
                swap(arr, i, j);
            }
        }
        swap(arr, i + 1, high);
        return i + 1;
    }

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

三、变体对比表格

变体名称 时间复杂度 空间复杂度 稳定性 主要特点 适用场景
基础快速排序 O(n log n)(平均), O(n²)(最坏) O(log n) 不稳定 简单高效,但可能退化到最坏情况 通用排序,数据无大量重复
三向切分快速排序 O(n log n)(平均), O(n)(大量重复元素) O(log n) 不稳定 优化重复元素场景,减少比较次数 数据包含大量重复值(如荷兰国旗)
随机化快速排序 O(n log n)(平均), O(n²)(最坏概率极低) O(log n) 不稳定 随机基准降低最坏情况概率 需要高概率避免最坏情况的场景
迭代实现(非递归) O(n log n)(平均), O(n²)(最坏) O(log n) 不稳定 避免递归栈溢出,适合大数组 大数据或栈深度受限的环境

四、关键选择原则

  1. 基础场景:优先使用基础快速排序,因其平衡性能和实现简单性。
  2. 重复元素 :三向切分快速排序可显著提升效率(如处理 1000 个重复值的数组)。
  3. 最坏情况规避:随机化版本适用于需要降低最坏时间复杂度概率的场景。
  4. 递归限制:迭代实现适合处理超大数组或栈深度受限的环境。
  5. 稳定性需求:所有变体均不稳定,若需稳定排序需选择其他算法(如归并排序)。

通过选择合适的变体,可在特定场景下优化性能或避免算法退化。例如,三向切分在处理重复元素时效率远高于基础版本,而随机化版本则能有效避免逆序数据导致的 O(n²) 时间。

相关推荐
明月看潮生21 分钟前
青少年编程与数学 02-016 Python数据结构与算法 29课题、自然语言处理算法
python·算法·青少年编程·自然语言处理·编程与数学
SuperherRo1 小时前
Web开发-JavaEE应用&原生和FastJson反序列化&URLDNS链&JDBC链&Gadget手搓
java·java-ee·jdbc·fastjson·反序列化·urldns
竹下为生2 小时前
LeetCode --- 154双周赛
算法·leetcode·哈希算法
xxjiaz2 小时前
二分查找-LeetCode
java·数据结构·算法·leetcode
算法练习生2 小时前
数据结构学习笔记 :排序算法详解与C语言实现
数据结构·学习·排序算法
nofaluse2 小时前
JavaWeb开发——文件上传
java·spring boot
爱的叹息3 小时前
【java实现+4种变体完整例子】排序算法中【插入排序】的详细解析,包含基础实现、常见变体的完整代码示例,以及各变体的对比表格
java·算法·排序算法
6v6-博客3 小时前
2024年网站开发语言选择指南:PHP/Java/Node.js/Python如何选型?
java·开发语言·php
Miraitowa_cheems4 小时前
[Java EE] Spring AOP 和 事务
java·java-ee·aop·spring 事务