Hello大家好! 很高兴与大家见面! 给生活添点快乐,开始今天的编程之路。
我的博客: <但愿.
文章专栏 :算法与数据结构
若有问题评论区下讨论,我会及时回答
欢迎大家点赞、关注、收藏分享
目录
一 排序的概念及应用
1排序概念
2排序的应用
二 插入排序
1插入排序的基本思想
2直接插入排序
2.1直接插入排序的基本思想
2.2直接插入的代码实现
2.3直接插入排序的时间复杂度
3希尔排序(缩⼩增量法)
3.1希尔排序的引入
3.2希尔排序的基本思想
3.3希尔排序的代码实现
3.4希尔排序的特性和时间复杂度
三 选择排序
1选择排序的基本思想
2直接选择排序
2.1直接选择排序的基本思想
2.2直接选择排序的代码实现
2.3直接选择排序的时间复杂度
3堆排序
3.1堆排序的基本思想
3.2堆排序的代码实现
四交换排序
1交换排序的基本思想
2冒泡排序
2.1冒泡排序的基本思想
2.2冒泡排序的代码实现
2.3直接选择排序的时间复杂度
3快速排序
3.1快速排序的递归版本
3.1.1快速排序的递归版本的基本思想
3.1.2快速排序的递归版本的三种实现方法:[这里我们是通过找基准值的方法来划分]
3.1.2.1快速排序的递归版本之hoare版本
3.1.2.2快速排序的递归版本之挖坑法版本
3.1.2.3快速排序的递归版本之lomuto前后指针版本
3.2快速排序的非递归版本
3.2.1快速排序的非递归版本基本思路
3.2.2快速排序的非递归版本代码实现
五归并排序
1归并排序的递归版本
1.1归并排序递归版本的基本思路
- 2归并排序递归版本核⼼步骤图解
1.3归并排序递归版本的代码实现
1.4归并排序递归版本的时间复杂度
2归并排序的非递归版本
2.1归并排序递非归版本的基本思路
- 2归并排序飞递归版本核⼼步骤图解
六非比较排序【这里只讲一种】
1计数排序
1.1计数排序的基本思路
1.2怎么创建一个合理的数组统计元素出现次数
1.3计算排序的代码实现
1.4计数排序的时间复杂度
七 排序算法复杂度及稳定性分析
排序导图

一 排序的概念及应用
1排序概念: 所谓排序,就是使⼀串记录,按照其中的某个或某些关键字的⼤⼩,递增或递减的排列起来的操作。
**2排序的应用:**排序在我们的生活中应用很广例如:购物筛选排序、院校排名、网课每节课的时间顺序等等。
二 插入排序
1插入排序的基本思想: 把待排序的记录按其关键码值的⼤⼩逐个插 ⼊到⼀个已经排好序的有序序列中,直到所有的记录插⼊完为⽌,得到⼀个新的有序序列 。
2 直接插入排序
2.1直接插入排序的基本思想:把待排序的记录按其关键码值的⼤⼩逐个插入到⼀个已经排好序的有序序列中,直到所有的记录插⼊完为⽌,得到⼀个新的有序序列 。(那这里我们怎么得到一个有序序列呢?我们把需要排序的序列分为两个序列把的一个数作为一个序列,其他的作为另一个序****列,这样我们就可以把只有一个数的序列作为有序序列)
2.2直接插入的代码实现

2.3直接插入排序的时间复杂度

这里我们假设数组的数据个数为n个,
那么第二个数据最多向前调整1次;
那么第三个数据最多向前调整2次;
那么第四个数据最多向前调整3次; . . . . . .. . .. .. . .. . .
那么第n个数据最多向前调整(n-1)次;
所以最多调整1+2+3+4+........+(n-1)=n^2,所以直接插入排序的时间复杂度是O(n^2);
这是直接插入排序的最坏情况, 此时直接插入排序的时间复杂度是O(n^2);
最好的情况是数组已是有序数组此时直接插入排序的时间复杂度是O(n);
综上:直接插入排序的最坏情况时间复杂度是O(n^2),满足这种情况只有一种必须是降序,
当数组中大的数据在前的越多时间复杂度就越靠近O(n^2);
直接插入排序的最好情况时间复杂度是O(n),当数组中小的数据在前的越多时间复杂度就越
靠近O(n);
所以直接插入排序的时间复杂度是介于O(n)和O(n^2)之间大多数情况小于O(n^2)只有一种情
况取到O(n^2)
3 希尔排序(缩⼩增量法)
3.1希尔排序的引入:上面的直接插入排序的时间复杂度是O(n^2), 只有当数组中小的数据在前的越多时间复杂度就越 靠近O(n);所以直接插入排序并不是很好,为了解决这个问题我们引入希尔排序(缩⼩增量法),我们前面先进行几次预排序将数组中小的时间移到数组的前面,最后一次进行直接插入排序,这样就可以大大减小时间复杂度,所以希尔排序(缩⼩增量法)的思想和直接插入排序的很像。
3.2希尔排序的基本思想:先选定⼀个整数(通常是gap = n/3+1),把待排序⽂件所有记录分成各组,所有的距离相等的记录分在同⼀组内,并对每⼀组内的记录进⾏排序,然后gap=gap/3+1得到下⼀个整数,再将数组分成各组,进⾏插⼊排序,当gap=1时,就相当于直接插⼊排序。
图示:

3.3希尔排序的代码实现:

3.4希尔排序的特性和时间复杂度
希尔排序的特性:
希尔排序是对直接插⼊排序的优化。
当 gap > 1 时都是预排序,⽬的是让数组更接近于有序。当 gap == 1 时,数组已经接近
有序的了,这样就会很快。这样整体⽽⾔,可以达到优化的效果。
希尔排序的时间复杂度:
我们将其分为内外两层分析:
外层循环**:**
外层循环的时间复杂度可以直接给出为: O (log2 n ) 或者 O (log3 n ) ,即 O (log n )【这里 我们可以把表达式近似认为是gap=gap/3便可以得到 外层循环的时间复杂度】
内层循环:
假设⼀共有n个数据,合计gap组,则每组为n/gap个;
gap取值有(以除3为例):n/3 n/9 n/27 ...... 2 1
•当gap为n/3时,移动总数为: 3 */*n * (1 + 2) = n ;
•当gap为n/9时,移动总数为:9/n *(1+2+3+....+8)=4n;
•最后⼀躺,gap=1即直接插⼊排序,内层循环排序消耗为n
希尔排序的时间复杂度= 外层循环的时间复杂度 * 内层循环的时间复杂度
所以希尔排序的时间复杂度由图像表示:
从上图可以看出希尔排序的时间复杂度与图像顶值有关,所以希尔排序的时间复杂度是计算不来的我们**一般取O(n^1.3),**可以查阅《数据结构(C语⾔版)》--- 严蔚敏书。
三 选择排序
1选择排序的基本思想:每⼀次从待排序的数据元素中选出最⼩(或最⼤)的⼀个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。
2 直接选择排序
2.1直接选择排序的基本思想
2.1.1 在元素集合 array[i]--array[n-1] 中选择关键码最⼤(⼩)的数据元素。
2.1.2 若它不是这组元素中的最后⼀个(第⼀个)元素,则将它与这组元素中的最后⼀个(第⼀个)元素 交换(即把最值放到最前和最后一个数据元素中)。
2.1.3 在剩余的array[i+1]--array[n-1]集合中(因为我们已经完成一次将最大与最小值放到最前和最后一个数据元素中 所以我们要对第[i+1]到第[n-1]中的数据元素重复进行1,2步)重复进行上述步骤,直到集合剩余 1 个元素
2.2直接选择排序的代码实现

2.3 直接选择排序的时间复杂度:时间复杂度: O(n^2 ),因为其效率不是很好,实际中很少使⽤。
3 堆排序
3.1堆排序的基本思想:将数组建堆,在利⽤堆积树(堆)这种数据结构所设计的⼀种排序算法 。利用堆顶是最值,先将堆顶与最后一个元素交换,在对除了最后一个元素的所有元素进行调整 (这里有两种调整方法向下/向上调整法,这里我们利用向下调整法因为向下调整时间复杂度比向上调整更小)需要注意的是排升序要建⼤堆,排降序建⼩堆。
3.2堆排序的代码实现

四 交换排序
1交换排序的基本思想: 根据序列中两个记录键值的⽐较结果来对换这两个记录在序列中的位置 交换排序的特点是:将键值较⼤的记录向序列的尾部移动,键值较⼩的记录向序列的前部移动。
2冒泡排序
2.1冒泡排序的基本思想:相邻两个元素进行比较大小。
2.2冒泡排序的代码实现:

**2.3冒泡排序的时间复杂度:**从上面可以知道冒泡算法的时间复杂度是o(N^2)从数据复杂度上来看这种排序算法并不好,所以我们很少使用这种排序。
3 快速排序
3.1快速排序的递归版本:
3.1.1快速排序的递归版本的基本思想:任取待排序元素序列中的某元素作为****基准值,**按照该排序码将待排序集合分割成两⼦序列,**左⼦序列中所有元素均小于基准值,右⼦序列中所有元素均⼤于基准值,然后最左右⼦序列重复该过程,直到所有元素都排列在相应位置上为⽌。【所以其中的操作包括找基准之,而找基准值的方法有三种】
3.1.2快速排序的递归版本的三种实现方法:【这里我们是通过找基准值的方法来划分】
3.1.2.1快速排序的递归版本之hoare版本:
**基本思路:**1)先要确保该排序码的元素个数至少要俩个
2)创建左右指针,确定基准值 。
3)从右向左找出⽐基准值⼩的数据,从左向右找出⽐基准值⼤的数据,左右指针 指向的数据交换,进⼊下次循环,直到找到基准值并返回。
4)通过返回的基准值将该排序码分为左右两序列,分别对两个序列重负上述步即 可(递归实现)
快速排序的递归版本之hoare版本代码实现:

快速排序的递归版本之hoare版本的时间复杂度
递归复杂度=单次递归的时间复杂度*递归次数;
分析上面代码我们可以知道单次递归的时间复杂是确定的即O(n)
而递归次数我们可以通过二叉树的节点个数和二叉树的高度之间的关系可以知道一般情况下是(logn)次。
下面我们来分析两种情况:1 当要排序的序列是有序的、2 基准值找的不好(首尾其中一个是基准值时),而这两种情况都要一样的相同点即它们在分左右序列时总有一个序列只有一个数据,此时递归次数就是n次。
综上快速排序的递归版本之hoare版本的时间复杂度是:
1一般情况下是:On*(logn);
2当要排序的序列是有序的、基准值找的不好(首尾其中一个是基准值时)下是:O(n^2);
3.1.2.2快速排序的递归版本之挖坑法版本:
快速排序的递归版本之挖坑法版本基本思路:创建左右指针。⾸先从右向左找出⽐基准⼩的数据,找到后⽴即放⼊左边坑中,当前位置变为新的"坑",然后从左向右找出⽐基准⼤的数据,找到后⽴即放⼊右边坑中,当前位置变为新的"坑",结束循环后将最开始存储的分界值放⼊当前的"坑"中,返回当前"坑"下标(即分界值下标)
快速排序的递归版本之挖坑法版本代码实现

3.1.2.3快速排序的递归版本之lomuto前后指针版本:
基本思路:创建前后指针,从左往右找⽐基准值⼩的进⾏交换,使得⼩的都排在基准值的左边。 1) cur指向的数据比基准值小,++prev,prev和cur指向的数据进行交换。
2)cur指向的数据不比基准值小,cur后移
快速排序的递归版本之lomuto前后指针版本代码实现:

快速排序的递归版本之lomuto前后指针版本时间复杂度:递归复杂度=单次递归的时间复杂度*递归次数;而单次递归的时间复杂度的时间复杂度从代码上分析可得是O(N),而递归次数我们可以根据二叉树中节点个数和二叉树的高度之间的关系可知递归次数是(logn)所以快速排序的递归版本之lomuto前后指针版本时间复杂度=O(N*logn);
3.2快速排序的非递归版本:
3.2.1快速排序的非递归版本基本思路:
前面的递归版本我们是之间通过创建left,right从而通过这两个变量知道数组的首尾。而非递归版本我们不创建变量指向数组的首尾,而是将数组首尾对应的下标入栈(根据栈的特点先进后出,所以先将数组尾部对应的下标入栈,在将头部对应的下标入栈)后续在连续取栈中两个数据便可以得到数组,但分出的左右序列中只有一个元素时数组的首尾对应的下标就不入栈。
3.2.2快速排序的非递归版本代码实现

五 归并排序
1 归并排序的递归版本
1.1归并排序递归版本的基本思路: 归并排序顾名思义是建⽴在归并操作上的⼀种有效的排序算法,该算法是采⽤分治法的⼀个⾮常典型的应⽤。将已有序的⼦序列合并,得到完全有序的序列;核心思想**:即先使每个 ⼦序列有序,再使⼦序列段间有序[怎么得到有序序列,这里通过中中间元素下标,在不断划分两个序列,知道每个划分出了的序列只有一个元素时就是有序的]** 。若将两个有序表合并成⼀个有序表,称为****⼆路归并。
1.2归并排序递归版本核⼼步骤图解:

1.3归并排序递归版本的代码实现:

4归并排序递归版本时间复杂度:
归并排序时间复杂度=分解数组时间复杂度合并两个*有序序列的时间复杂度=O(N*logN)
通过代码分析可以知道分解数组和二叉树一样所以分解数组时间复杂度=O(logn)
合并两个有序序列的时间复杂度=O(n):
2归并排序的非递归版本
2.1归并排序的非递归版本的基本思路 :前面的递归版本,是将序列分解的时候不断分成两个序列,到最后分出的每个序列元素个数一定只有一个,那这里我们可以反过来就不用递归了。先创建一个变量来记录序列中元素的个数,先将其赋值为1,此时序列不就全都是有序序列。在合并有序序列,合并后让gap*2在重复上诉步骤,直到gap>数组中元素个数是跳出循环。
这里有一个问题因为我们记录序列中元素的个数是不断*2的(即不可能是奇数)这就引处一个问题,如果数组元素个数是偶数个没什么事,**但是如果数组中元素个数是奇数个此时第二个有序序列的元素个数要么没有,要么元素个数<gap,**此时不作出改变,就会有随机数填充。
当第二个有序序列的的一个下标>原数组中元素的个数,此时说明第二个序列是没有元素的,应该跳出循环
未满足上面条件不就说明此时第二个序列中是有元素的,但要判断此时序列中是否有gap个元素,**当第二个序列的最后一个有序的下标>=n,**此时说明第二个序列中元素没有gap个,应让end指向原数组中最后一个元素的下标
2.2归并排序的非递归版本代码实现

六 非比较排序【这里只讲一种】
1计数排序
1.1计数排序的基本思路 :计数排序⼜称为鸽巢原理,是对哈希直接定址法的变形应⽤。操作步骤:1)统计元素出现次数
2)根据统计的结果将序列回收到原来的序列中
1.2怎么创建一个合理的数组统计元素出现次数

1.3计算排序的代码实现:

**1.4计数排序的时间复杂度:**从上面代码分析可知是O(N+range)因为这里不知道n与range的大小关系所以不能省略。
七 排序算法复杂度及稳定性分析
1****稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,⽽在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

本篇文章就到此结束,欢迎大家订阅我的专栏,欢迎大家指正,希望有所能帮到读者更好了算法与数据结构相关知识 ,觉得有帮助的还请三联支持一下~后续会不断更新算法与数据结构相关知识,我们下期再见。