手撕快速排序

1.思想:

(1)分治策略 + 原地排序。

(2)选择一个基准元素(pivot),将数组分成两部分:左边部分 <= 基准;右边部分 >= 基准。

(3)递归地对左右两部分进行同样的操作。

2.算法步骤:

(1)选择基准(如第一个、最后一个、或随机)。

(2)分区(partition):通过交换将元素放到基准两侧。

(3)递归处理左右子数组。

3.复杂度与特点:

(1)时间复杂度:

(a)平均时间复杂度:O(nlogn)。

(b)最坏情况下的时间复杂度(数组已经正序或逆序排序,并且基准元素选择的是队首或队尾):O(n^2)。

(c)最好情况下的时间复杂度:O(nlogn)。

(2)空间复杂度:O(logn)(递归栈)。

(3)快速排序是否稳定:不稳定,交换可能改变相等元素的相对顺序。

(4)特点:原地排序,常数因子小,实际应用中通常比归并排序快。

附代码:

java 复制代码
class QuickSort {
    public void quickSort(int[] nums, int left, int right) {
        if (left >= right) {
            return;
        }
        int pivotIndex = partition(nums, left, right);
        quickSort(nums, left, pivotIndex);
        quickSort(nums, pivotIndex + 1, right);
    }

    private int partition(int[] nums, int left, int right) {
        // 选择中间元素作为基准
        int pivot = nums[left + (right - left) / 2];
        int i = left;
        int j = right;

        while (true) {
            // 从左向右找第一个 >= pivot 的元素
            while (nums[i] < pivot) {
                i++;
            }
            // 从右向左找第一个 <= pivot 的元素
            while (nums[j] > pivot) {
                j--;
            }
            // 如果指针相遇或交叉,分区结束
            // 此时j指向左半部分的结尾,i指向右半部分的开头
            // 所以是return j
            if (i >= j) {
                return j;
            }
            // 交换
            swap(nums, i, j);
            i++;
            j--;
        }
    }

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

ACM模式:

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

class QuickSort {
    public void quickSort(int[] nums, int left, int right) {
        if (left >= right) {
            return;
        }
        int pivotIndex = partition(nums, left, right);
        quickSort(nums, left, pivotIndex);
        quickSort(nums, pivotIndex + 1, right);
    }

    private int partition(int[] nums, int left, int right) {
        // 选择中间元素作为基准
        int pivot = nums[left + (right - left) / 2];
        int i = left;
        int j = right;

        while (true) {
            // 从左向右找第一个 >= pivot 的元素
            while (nums[i] < pivot) {
                i++;
            }
            // 从右向左找第一个 <= pivot 的元素
            while (nums[j] > pivot) {
                j--;
            }
            // 如果指针相遇或交叉,分区结束
            // 此时j指向左半部分的结尾,i指向右半部分的开头
            // 所以是return j
            if (i >= j) {
                return j;
            }
            // 交换
            swap(nums, i, j);
            i++;
            j--;
        }
    }

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

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] nums = new int[n];
        for (int i = 0; i < n; i++) {
            nums[i] = scanner.nextInt();
        }

        QuickSort quickSort = new QuickSort();
        quickSort.quickSort(nums, 0, n - 1);

        for (int i = 0; i < n; i++) {
            System.out.print(nums[i]);
            if (i < n - 1) {
                System.out.print(" ");
            }
        }
        System.out.println();
        scanner.close();
    }
}
相关推荐
CSharp精选营4 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
刘马想放假7 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠8 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
Darling噜啦啦15 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
小小工匠16 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾16 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
Qres82116 天前
算法复键——树状数组
数据结构·算法
牛油果子哥q16 天前
并查集(DSU)超精讲,路径压缩、按秩合并、万能模板、连通性判定、最小生成树与刷题实战全解
数据结构·c++·最小生成树·并查集
凌波粒16 天前
LeetCode--491.递增子序列(回溯算法)
数据结构·算法·leetcode
WL学习笔记16 天前
单项不带头不循环链表
数据结构·链表