【0基础学算法】快速排序(超详细讲解+私人笔记+源码)上

简介: 笔记

前言:


大家好,这是0基础学算法的第一课,当然这个0基础并不是我们常规意义上的0基础,你需要掌握一点语法知识即可学习此课程,夸张点说会敲“Hello World”就行/doge。当然这是一个系列课,我将由简到深的为大家讲解一些算法知识,从排序到搜索以及更多,也希望这个系列可以给你带来帮助。算法学习是个很难的过程,希望你可以在此过程中坚持下来,加油!


附:系列中出现较难的知识点或者语法知识我都会作讲解,如果还有什么不明白的知识可以在下方评论,本人看到后会立即回复滴。


知识讲解:


下面直接开始我们今天所要讲解的知识——快速排序。


快速排序重要性:

快速排序是我们在编程技术中十分常见的一种排序方式,其由于排序效率在同为O(N*logN)的几种排序方法中效率较高,所以经常会被采用,再加上处理快速排序时使用的分治法思想十分实用,这就导致了很多的软件公司(腾讯,微软等知名IT公司)在笔试面试的时候也会很喜欢考这个,还有我们在程序方面的考试(软考等)和一些比赛(PAT,蓝桥杯等)还有考研中都会经常出现他的身影。


快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。我们在实现快速排序的时候会采用一种分治的策略,也成为分治法(Divide-and-ConquerMethod)。


分治法的基本思想:

分治法可以通俗的解释为:把一片领土分解,分解为若干块小部分,然后一块块地占领征服,被分解的可以是不同的政治派别或是其他什么,然后让他们彼此异化。


实现步骤:

在我们今天学习的算法中,我们将其分为以下的三个步骤:


1.先从数列中取出一个数作为基准数。(确认边界点)

2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。(重新调整区间)

3.再对左右区间重复第二步,直到各区间只有一个数。(递归)

看完上面你也不妨看出我将其简化为:确认边界点-重新调整区间-进行递归。三个步骤去进行实现。在这三个步骤中,要注意的一点是:在进行确认边界点的时候我们要考虑确定的边界点是左边界?右边界?中点?随机?的同时也要考虑取哪个点更方便我们后续的操作。

5.png


如上文所说,我们在分区选点的时候会面临着四种选择,在这里我们选择取中间点为我们的分界点,在这里会有人问为什么不取其他的点呢,先说随机点,这个就相对来说比较麻烦,然后左右两个端点为什么不建议取呢,主要是左右两个端点与后面开区间时会有边界值无法通过的现象,我们在举出特殊例子时是可以看出的,在这里我就不为大家列举了,这个知识相对来说没那么重要,我们只需记得取中间点为分界点即可。


在经过第一步的思考后我们在进行分区的操作是也如下图所示:


6.png

快速排序分区过程实现简图

到这里我们距离实现快速排序也只差了一步,也就是我们的递归,这个递归就是我们就是不断分界,分到最小单元。(当然这个现在看不懂没关系,到后面的代码展示环节时会出现)


举例:

我为大家举一个实例来帮助大家理解。以一个数组作为示例,取区间中间数数为基准数(标红)。


数组7.png

然后我们将左右两个端点的下标记住,

8.png


之后的我们就将左右两个元素交换,交换后继续重复上述操作,直到两个指针相遇停止,也就是如下操作:

交换位置:9.png

之后继续移动直到相遇:

10.png

相遇的时候对应下标为:4 。这个时候明显可见我们数组中0-4的数字都是<=85的,而5-9的数字都是>85的。


所以我们就将数组一分为二(并不是真正意义上的分开),0-4分开进行排序,5-9分开进行排序。


排序的过程也就跟我们上面所描述的一样。


数组

0 1 2 3 4 5 6 7 8 9

82 24 73 71 85 94 88 90 86 93

相信聪明的各位已经看出来了,这里的一分为二就是在同一个数组上分开两次进行上述方法的交换。交换的具体过程我就不细写啦,结果如下:


数组

0 1 2 3 4 5 6 7 8 9

71 24 73 82 85 86 88 90 94 93

然后继续套娃,分开进行:


数组

0 1 2 3 4 5 6 7 8 9

71 24 73 82 85 86 88 90 94 93

数组

0 1 2 3 4 5 6 7 8 9

24 71 73 82 85 86 88 90 93 94

显而易见到这里我们的排序就完成啦,也成功的对这个数组进行了一次排序。


思路:

思路就是对上面步骤以及例子的总结。我之所以放到例子后面附上主要是希望大家通过看例子可以加深对这些的记忆。在这里我直接为大家附上图,希望大家更容易理解一些。


思路一:

思路一就是我们的暴力解法,直接开两个数组,然后找出分界点,将比分界点小以及大的数字分别放入两个数组,最后再归还为原数组。

11.png



思路二:

在这里思路二也就是我们上面举例子用的方法,也是我们今天主讲的思路,就是用双指针进行不断靠近。



快速排序实现:

在这里快速排序的实现我就为大家简化为下面几步:


第一步:开一个数组


第二步:输入元素个数


第三步:将每个元素输入


第四步:调用模板


非常的通俗易懂是吧,在这里大家都想知道这个模板是什么,所以我们的重头戏就来了!

模板:

模板的实现我给大家已画图的方式列出,字丑希望大家不要介意。


14.png


在这里你可能会疑惑,哎?这不就是刚才讲的那些内容吗,为什么还要再说一遍呢?


我之所以在这里再提到一遍,主要是因为在我们学算法刷题时,不是说只学那个方法就可以了,我们有很多要考虑的东西,有的边缘值了,范围了都需要我们考虑。就比如刚才模板中的1个数不用排序的情况,如果我只给你讲解了前面的知识,你可能会理解快速排序,但是你自己实现起来会有很大的难度,有很多是你很难想象的到的错误,所以大家不要嫌我讲的繁琐。/抱拳


模板的代码实现:

void quick_sort(int q[], int l, int r)
{
    if (l >= r) return;
    int i = l - 1 ;
    int j = r + 1 ;
    int x = q[l + r >> 1] ;
    while (i < j)
    {
        do i ++ ; 
            while (q[i] < x);
        do j -- ; 
            while (q[j] > x);
        if (i < j) 
        {
            swap(q[i], q[j]);
            }
    }
    quick_sort(q, l, j), quick_sort(q, j + 1, r);
}


好了,到了这里肯定有hxd会问:l+r>>1是什么意思。我在这直接为大家讲一下:


这里>> 就是二进制右移运算符。将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。


简单点来说 x>>1等价于x/2 。


为了方便大家学习,我直接把这两个公式给大家附上,希望大家可以看一下:


·        x >> n 等同于 x / (2^n)  ,x << n 等同于 x * (2^n)


实战

到这里大家对快速排序已经了解的差不多了,下面看几个简单的题目来巩固一下吧。





相关文章
|
3月前
|
算法 数据可视化 数据挖掘
基于EM期望最大化算法的GMM参数估计与三维数据分类系统python源码
本内容展示了基于EM算法的高斯混合模型(GMM)聚类实现,包含完整Python代码、运行效果图及理论解析。程序使用三维数据进行演示,涵盖误差计算、模型参数更新、结果可视化等关键步骤,并附有详细注释与操作视频,适合学习EM算法与GMM模型的原理及应用。
|
11月前
|
搜索推荐 C语言
【排序算法】快速排序升级版--三路快排详解 + 实现(c语言)
本文介绍了快速排序的升级版——三路快排。传统快速排序在处理大量相同元素时效率较低,而三路快排通过将数组分为三部分(小于、等于、大于基准值)来优化这一问题。文章详细讲解了三路快排的实现步骤,并提供了完整的代码示例。
359 4
|
6月前
|
算法 搜索推荐
快速排序-数据结构与算法
快速排序(Quick Sort)是一种基于分治法的高效排序算法。其核心思想是通过选择基准(pivot),将数组划分为左右两部分,使得左侧元素均小于基准,右侧元素均大于基准,然后递归地对左右两部分进行排序。时间复杂度平均为 O(n log n),最坏情况下为 O(n²)(如数组已有序)。空间复杂度为 O(1),属于原地排序,但稳定性不佳。 实现步骤包括编写 `partition` 核心逻辑、递归调用的 `quickSort` 和辅助函数 `swap`。优化方法有随机化基准和三数取中法,以减少最坏情况的发生。
439 13
|
7月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
8月前
|
机器学习/深度学习 自然语言处理 算法
生成式 AI 大语言模型(LLMs)核心算法及源码解析:预训练篇
生成式 AI 大语言模型(LLMs)核心算法及源码解析:预训练篇
1707 1
|
11月前
|
存储 搜索推荐 Python
用 Python 实现快速排序算法。
快速排序的平均时间复杂度为$O(nlogn)$,空间复杂度为$O(logn)$。它在大多数情况下表现良好,但在某些特殊情况下可能会退化为最坏情况,时间复杂度为$O(n^2)$。你可以根据实际需求对代码进行调整和修改,或者尝试使用其他优化策略来提高快速排序的性能
267 61
|
10月前
|
机器学习/深度学习 前端开发 算法
婚恋交友系统平台 相亲交友平台系统 婚恋交友系统APP 婚恋系统源码 婚恋交友平台开发流程 婚恋交友系统架构设计 婚恋交友系统前端/后端开发 婚恋交友系统匹配推荐算法优化
婚恋交友系统平台通过线上互动帮助单身男女找到合适伴侣,提供用户注册、个人资料填写、匹配推荐、实时聊天、社区互动等功能。开发流程包括需求分析、技术选型、系统架构设计、功能实现、测试优化和上线运维。匹配推荐算法优化是核心,通过用户行为数据分析和机器学习提高匹配准确性。
741 4
|
11月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
396 7
|
11月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
473 8
|
算法 API 计算机视觉
人脸识别笔记(一):通过yuface调包(参数量54K更快更小更准的算法) 来实现人脸识别
本文介绍了YuNet系列人脸检测算法的优化和使用,包括YuNet-s和YuNet-n,以及通过yuface库和onnx在不同场景下实现人脸检测的方法。
488 1

热门文章

最新文章