算法通关村——快速排序

深析快速排序

1、快速排序概念

​ 快速排序属于交换排序,通过元素之间的比较和交换位置来达到排序的目的。

​ 快速排序会在每一轮排序中挑选一个基准元素,并让其他比它大的元素移动到数组一边,比它小的元素移动到数组另一边,从而把数组拆解成两部分,如下图所示:

789bff53a103bec05106e821168ac257

​ 之后再重新在左部分和右部分各自执行快速排序,在将左右两个序列拍好序之后,整个序列就有序了。这里排序进行左右划分的时候是一直划分到子序列只包含一个元素的情况,然后再递归返回。具体的流程如下:

c5e5550d2e531a0517c946a0557fda78

​ 每一轮的比较和交换,需要把数组全部都遍历一遍,时间复杂度是O(n)。假设元素个数是n个,那么平均情况下需要logn轮,因此快速排序算法总体的平均时间复杂度是O(nlogn)。

2、快速排序的代码实现

​ 快速排序的核心框架就是**“二叉树的前序遍历 + 对撞型双指针”**,具体的代码如下:

public static void quickSort(int[] arr, int left, int right) {
    if (left < right) {
        int pivot = arr[right];
        int i = left - 1;
        for (int j = left; j < right; j++) {
            if (arr[j] < pivot) {
                i++;
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        //哨兵移动到位置pivotIndex上
        int pivotIndex = i + 1;
        int temp = arr[pivotIndex];
        arr[pivotIndex] = arr[right];
        arr[right] = temp;
        
        quickSort(arr, left, pivotIndex - 1);
        quickSort(arr, pivotIndex + 1, right);
    }
}

​ 下面结合具体的一个数组[26, 53, 48, 15, 13, 48, 32, 15]来看一下一次划分的过程。

快排过程

​ 这里i的作用就是负责索引比pivot小的元素,从上图中也可以看到,每发现一个比pivot小的元素,i就加1,同时把该元素调到i的位置,当一次排序结束后,我们可以使pivotIndex = i + 1,再把最开始的pivot对应的arr[right]调换到pivotIndex上,这样pivotIndex左边的元素就都是比pivot小的,右边的元素都是比pivot大的。

​ 快排还可以用下面这一种实现:

pubilc static void quickSort(int[] arr, int left, int right) {
    if (start >= end) {
        return;
    }
    //这里就是一个对撞的双指针操作
    int left = start;
    int right = end;
    int pivot = arr[(start + end) / 2];
    
    while (left <= right) {
        //这里是从左边开始找,找到一个比pivot大的元素,然后停下来
        while (left <= right && ar[left] < pivot) {
            left++;
        }
        //这里是从右边开始找,找到一个比pivot小的元素,然后停下来
        while (left <= right && ar[right] > pivot) {
            right--;
        }
        //将刚刚找到的两个元素调换位置,这样比pivot小的元素就在其左边,比他大的在右边
        if (left <= right) {
            int temp = arr[left];
            arr[left] = arr[right];
            arr[right] = temp;
            //调换完位置后继续往中间找
            left++;
            right--;
        }
        //直到left > right,这时pivot左边的元素都是比它小的,pivot右边的元素都是比它大的
    }
    
    //先处理元素再分别递归两侧分支,与二叉树的前序遍历非常像
    quickSort(arr, start, right);
    quickSort(arr, left, end);
}

3、复杂度分析

​ 快速排序的时间复杂度计算比较麻烦。从原理来看,如果我们选择的pivot每次都在正中间,效率是最高的,但是这是无法保证的,因此我们需要从最好、最坏的中间情况分析

  • 最坏情况就是如果每次选择的恰好都是low节点作为pivot,如果元素恰好都是逆序的,此时时间复杂度为O(n2)O(n^2)O(n2)

  • 如果元素刚好是有序的,则时间复杂度为O(n)O(n)O(n)

  • 这种的情况是每次选择的都是中间节点,此时序列每次都是长度相等的序列,此时时间复杂度为O(nlog2n)O(nlog_2n)O(nlog2n)

学习 JavaScript 数据结构算法是一个非常有价值的技能提升方向,尤其在前端开发和全栈开发中尤为重要。以下是一些推荐的学习资料和资源,帮助系统掌握 JavaScript 数据结构算法: ### 推荐书籍 1. **《学习 JavaScript 数据结构算法》**(第三版) 作者:Loiane Groner 这本书详细介绍了 JavaScript 中常见的数据结构(如栈、队列、链表、集合、字典等)以及基础和高级算法。书中代码示例丰富,适合初学者和中级开发者。 2. **《JavaScript 数据结构算法:小册》** 一本轻量级的中文电子书,适合快速入门,内容涵盖基础数据结构排序算法、图算法等内容。 3. **《数据结构算法分析——C语言描述》** 虽然使用 C 语言讲解,但理论基础扎实,适合理解算法的时间复杂度、空间复杂度等核心概念。 ### 在线课程 1. **LeetCode + Bilibili 算法课程** Bilibili 上有很多高质量的免费课程,例如“代码随想录”、“算法关手册”等系列,结合 LeetCode 刷题进行实践,效果显著。 2. **Coursera - Algorithms, Part I & II(Princeton University)** 由 Robert Sedgewick 教授主讲,虽然是 Java 语言实现,但对算法的理解非常有帮助。 3. **Udemy - JavaScript Algorithms and Data Structures Masterclass** 由 Colt Steele 主讲,专注于使用 JavaScript 实现经典算法,适合进阶学习。 ### 网站与刷题平台 1. **LeetCode** 提供大量编程题目,涵盖数组、字符串、链表、树、图、动态规划等主题,适合过实战提升算法能力。 2. **GeeksforGeeks** 提供丰富的算法解析和 JavaScript 实现示例,是查阅算法知识点的好去处。 3. **CodeWars** 过游戏化的方式提升编程能力,题目难度分级明确,适合日常练习。 ### 示例:JavaScript 实现一个链表 ```javascript class Node { constructor(data) { this.data = data; this.next = null; } } class LinkedList { constructor() { this.head = null; this.size = 0; } add(data) { const node = new Node(data); if (!this.head) { this.head = node; } else { let current = this.head; while (current.next) { current = current.next; } current.next = node; } this.size++; } print() { let current = this.head; const result = []; while (current) { result.push(current.data); current = current.next; } console.log(result.join(' -> ')); } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Molche

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值