冒泡排序 && 快排(hoare递归)

Posted Naxx Crazy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了冒泡排序 && 快排(hoare递归)相关的知识,希望对你有一定的参考价值。

今天要讲一个是冒泡排序,进一个是快排,首先是冒泡排序,我相信大家接触的第一个排序并且比较有用的算法就是冒泡排序了,冒泡排序是算法里面比较简单的一种,所以我们先看看一下冒泡排序

还是个前面一样,我们先看一下单趟排序

假设我们又以下数组

我们想要对他进行排序

那么此时我们先看第一个位置和第二个位置

 

i和j位置,如果这里i位置的值大于j位置的值,那么我们就让他们交换,否则就让i和j同时向后走一位

 

 让i和j位置的值进行交换,然后让i和j同时向后走一位

 然后就继续比较i和j位置的值

 然后最后排好就是这样子的,此时我们一趟就排序结束了,这时候我们可以看到,我们数组的最后一个元素是最大的,所以我们继续排序,从第0和位置开始到现在9后面的位置,依次比较,如果i大于j位置的元素就交换否则就让i和j同时向后走

下面我们就看一下代码

代码也是很简单基本没什么好看的

下面我们看一个🐂的排序 ,快排,听名字就知道一定很快

下面就看一下

假设我们是这一组数据

 我们先说思想,这里就是先选一个数,然后左边找比选定的key大的,右边找小的,然后两个位置交换,然后让最后两个位置相遇后与key位置的值交换,最后就可以让key位置的值的左边都是比key小的,右边都是比key大的

就是这样,所以我们现在来看一下

 首先左边找大,右边找小,然后找到了就交换

 然后继续找,找到了就交换

 最后直到left不小于right说明就剩下最后一个了,然后我们就让相遇的位置与key位置的值交换,最后我们就可以看到

6的左边都是小于他的,6的右边都是大于他的

到了这里我们一趟排序就结束了,我们想一下刚才排序的过程,我们用左边第一个值作为key,然后我们右边先开始找的小于key位置的值,我们这里就先记住,如果是左边为key那么就右边先走,如果右边为key那么就左边先走,其中这里的key并不是某一个固定的值,我们可以选数组其他位置的值为key但是那样的话容易出错,所以我们可以选择左边或者右边的值为key,那么这样我们就一趟排序结束了

这时候我们就可以想,怎么样可以把他排序好

我们这时候继续看一下

 

这时候我们的6已经拍好了,所以我们就不需要在管6了,我们就可以让他继续 

递归下去,以一边的right以6这个位置-1为末尾,另一边以6这个位置+1为起始点

 

 然后我们继续递归

就这样下去我们就可以依次拍好,让每一个值的左边都是小于他的右边都是大于他的,这里我们认为如果只剩下一个数字那么就是有序的。所以这里如果l不小于r那么就 只剩下一个数字

最后排序好就是这样

 就是这样,然后我们就排序好了

下面我们就来看一下代码

 

 首先我们这里定义key为left,然后我们就开始找大和小,然后让他们交换,知道left不小于right说明已经找完了,最后让left和right相遇的位置和key位置的值交换,然后就进行递归

你们可以画一下递归展开图

就是这样,主要是这里画递归展开图太麻烦了,就不画了,而且之前在树遍历那一块画了很多遍,思想已经传达到了

这个就是快排

完了介绍快排的时间复杂度

 

 

Java版算法思想(排序)选择&冒泡&快排

本文代码已上传github: https://github.com/chenruoyu0319/data-structure-for-java/tree/main/%E9%80%89%E6%8B%A9%26%E5%86%92%E6%B3%A1%26%E5%BF%AB%E6%8E%92%EF%BC%88%E6%8E%92%E5%BA%8F%EF%BC%89

一、选择排序

选择排序的思路和插入排序非常相似,也分已排序和未排序区间。但选择排序每次会从未排序区间中找到最小的元素,将其放到已排序区间的末尾(即未排序区间的第一个)。但是不像插入排序会移动数组,选择排序会每次对元素进行交换,如以下例子:

4 5 6 3 2 1

第一次: 1 5 6 3 2 4

第二次: 1 2 6 3 5 4

每次确保排完一个数

分析:

1.时间复杂度:O(N^2)

2.空间复杂度:O(n)

3.交换次数: 比较多

4.稳定性:不稳定

二、冒泡排序

核心思路:冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求。如果不满足就让它俩互换。一次冒泡会让至少一个元素移动到它应该在的位置,重复n次,就完成了n个数据的排序工作。

举例说明:4 5 6 3 2 1,从小到大排序。

1 2 3 4 5 6进行排序:什么样的情况下不做任何交换了呢,那就是所有的数都在它应该在的位置;O(n)

第一次冒泡的结果:4 5 6 3 2 1->4 5 3 6 2 1 - > 4 5 3 2 6 1 -> 4 5 3 2 1 6,哪个元素的位置确定了,6

第二次冒泡的结果:4 5 3 2 1 6->4 3 5 2 1 6 -> 4 3 2 5 1 6 -> 4 3 2 1 5 6

第三次冒泡的结果:4 3 2 1 5 6->3 4 2 1 5 6 -> 3 2 4 1 5 6 -> 3 2 1 4 5 6

第四次冒泡的结果:3 2 1 4 5 6->2 3 1 4 5 6 -> 2 1 3 4 5 6

第五次冒泡的结果:2 1 3 4 5 6->1 2 3 4 5 6

分析:

1.时间复杂度:O(n^2)

2.空间复杂度:O(n)

3.交换次数:挺大的

4.稳定性:稳定

三、快速排序

45 28 80 90 50 16 100 10

基准数:一般就是取要排序序列的第一个。

第一次排序基准数:45

从后面往前找到比基准数小的数进行对换:

10 28 80 90 50 16 100 45

从前面往后面找比基准数大的进行对换:

10 28 45 90 50 16 100 80 进行了一次部分排序

下一次部分排序

10 28 16 90 50 45 100 80

再下一次部分排序

10 28 16 45 50 90 100 80

以基准数分为3部分,左边的比之小,右边比之大:

10 28 16 45 50 90 100 80

到此第一次以45位基准数的排序完成。

四、对快速排序的分析

1.时间复杂度:nlogn 最坏的情况就是O(n^2)

2.空间复杂度:O(n)

3.稳定性:不稳定

4.快排和归并的对比:

(1)归并排序的处理过程是由下到上的,先处理子问题,然后再合并。

(2)快排其实就是从上到下,先分区,在处理子问题,不用合并。

5.快排的优化:

三数取中(选基准)+插排(优化)+三向切分聚集重复值(优化)的时间复杂度同STL中的Sort近似。

最理想的方法是,选择的基准恰好能把待排序序列分成两个等长的子序列

1、随机选取基准:在待排序列是部分有序时,固定选取枢轴使快排效率底下,要缓解这种情况,就引入了随机**选取枢轴。

思想:取待排序列中任意一个元素作为基准。

2、三数取中:使用左端、右端和中心位置上的三个元素比较,大小为中值**的作为枢纽元。

注:使用三数取中选择枢轴优势还是很明显的,但是还是处理不了重复数组

3、**引入插入排序:**在数组长度大于某一个阈值范围时,我们进行递归快排;当数据长度小于阈值时,我们进行插入排序。

4、**三向切分法(聚集重复值):**在一次分割结束后,可以把与Key相等的元素聚在一起,继续下次分割时,不用再对与key相等元素分割。

具体过程有两步:一在划分过程中将与基准值相等的元素放入数组两端;二划分结束后,再将两端的元素移到基准值周围。

主要用于具有大量重复数据的情况,可以大大提高效率,因为正常的快排同样会把这些重复数进行递归。

五、各种排序对比

排序名称时间复杂度是否稳定额外空间开销
插入排序O(n^2)稳定O(1)
冒泡排序O(n^2)稳定O(1)
选择排序O(n^2)不稳定O(1)
希尔排序O(n^2)不稳定O(1)
归并排序O(nlogn)稳定O(n)
快速排序O(nlogn)不稳定O(1)

这么多种排序算法我们究竟应该怎么选择呢?:

1.分析场景:稳定还是不稳定

2.数据量:数据量小的时候选什么?比如就50个数,优先选插入或冒泡

大数据量(5000*5000=25000000),优先选择快排或归并

3.分析空间:

综上所述,没有一个固定的排序算法,都是要根据情况分析的。但是如果你不会分析的情况下,就选择归并或者快排。

实例:C++ qsort:快排+插入排序

,优先选插入或冒泡

大数据量(5000*5000=25000000),优先选择快排或归并

3.分析空间:

综上所述,没有一个固定的排序算法,都是要根据情况分析的。但是如果你不会分析的情况下,就选择归并或者快排。

实例:C++ qsort:快排+插入排序

jdk里面有Arrays.sort:基础类型比如int double 用的快排,对象排序,用的是归并+timeSort。

以上是关于冒泡排序 && 快排(hoare递归)的主要内容,如果未能解决你的问题,请参考以下文章

Java版算法思想(排序)选择&冒泡&快排

快速入手八大排序,带你从入门到精通

插入.希尔.选择.堆排.冒泡.快排.归并.计数_8排序

排序(ACM模式)冒泡选择插入快排

排序(ACM模式)冒泡选择插入快排

排序(ACM模式)冒泡选择插入快排