十大经典排序算法总结
算法复杂度
- 算法复杂度分为时间复杂度和空间复杂度:
- 时间复杂度:执行这个算法所需要的计算工作量
- 空间复杂度:执行这个算法所需要的内存空间
空间复杂度
- 利用程序的空间复杂度,可以对程序运行所需要的内存空间有个预估;
- 程序执行所需要的内存空间包括以下两个部分:
- 固定空间:只要包括指令空间(即代码空间),数据空间(常量,简单变量)等所占的空间
- 可变空间:主要包括动态分配的空间,以及递归栈所需要的空间
时间复杂度
-
T(n)=n^2+3n+4 T(n)=4n^2-5n+3
-
为了描述时间频度的变化规律,引入了时间复杂度概念,记为O(…)
-
时间复杂度的计算规则:
- 当不存在变量时,用常数1来取代时间频度中所有的加法常量
- 当存在变量时,常量直接舍去
- 只要高阶项,舍去低阶项
- 不要高阶项系数
-
时间频度不同,但是时间复杂度可以相同:
- T(n)=n2+3n+4—>n2+3n—>n2
- T(n)=4n2-5n+3—>4n2-5n—>4n2—>n2
-
常见的时间复杂度(依次从低到高):
-
复杂度 名称 O(1) 常数阶 O(logn) 对数阶 O(n) 线性阶 O(n*log n) 线性对数阶 O(n^2) 平方阶 O(n^3) 立方阶 O(n^k) k次方阶(k>3且k∈Z) O(2^n) 指数阶
-
十大排序算法(默认升序)
-
冒泡排序
- 从索引0开始,当前索引位置的数据和下个索引位置的数据进行比较
- 如果当前数据大于下个数据,则位置互换,重复第一过程继续比较,直到最后一个数据
- 一轮结束后,最后一个数据就是最大的数据,再次从索引0位置开始,重复上面过程,直到倒数第二个数据
- 时间复杂度:O(n^2)
-
选择排序
- 假设索引为0的数据最小
- 依次和其他索引位置的数据进行比较
- 当其他索引位置的数据更小时,则位置互换,并且将新的索引为0的数据继续比较下去,直到最后一个
- 一轮结束后,索引0位置的数据就是最小的数据,从索引1开始,重复上面过程
- 时间复杂度O(n^2)
-
插入排序
- 从索引0位置的数据开始,加入索引1位置的数据
- 将新加入的数据依次和旧序列的数据进行比较
- 当新数据大于前一个数据且小于后一个数据时,则将新数据插入到这两个数据中,组成新的升序序列
- 一次插入结束后,加入索引2位置的数据,重复上面过程
- 时间复杂度O(n^2)
-
希尔排序(Shell)
- 希尔排序其实是插入排序的一种改进算法
- 将原序列长度除以2进行分组,再进行插入排序
- 如动态图所示,跨度依次为5,2,1,被称为希尔排序的增量
- 在大多数元素已经有序的情况下,插入排序的工作量降低
- 上面每一轮的希尔增量是等比的,因此导致了希尔增量存在盲区(例:{2,1,5,3,7,6,9,8})
- 最具代表性的希尔增量:Sedgewick的增量序列,依次为1, 5, 19, 41, 109…,通项公式4^k - 3*2^k + 1
- 时间复杂度O(n^4/3)
- 稳定性:不稳定
-
快速排序
- 快速排序其实是冒泡排序的一种改进算法
- 时间复杂度O(n*logn)
- 如果基准点没有选好,有可能导致冒泡排序
- 稳定性:不稳定
- 快速排序需要将所有的数据放入内存依次排完。
-
归并排序
-
核心思路:将两个有需要的序列进行比较,依次从两个队列取出最小的数据进行比较,然后将更小的数据存入合并后的序列中,并且从原序列中去除
-
时间复杂度O(n*logn)
-
会占用两倍的内存空间
-
分割
- 依次将序列二等分,二等分之后的字序列继续二等分
- 直到每组序列只有一个数据时,停止分割
-
合并
- 按照分割的顺序反向合并,并且做升序排序![在这里插入图片描述](https://img-blog.csdnimg.cn/2020121714453067.gif
- 按照分割的顺序反向合并,并且做升序排序![在这里插入图片描述](https://img-blog.csdnimg.cn/2020121714453067.gif
-
-
堆排序
- 每个父节点的值都大于或等于子节点的值,称为大顶堆;每个父节点的值都小于或者等于子节点的值,称为小顶堆;
- 二分查找树
- 任意节点
- 最多有两个子节点
- 左面的子节点都小于或等于父节点
- 右面的子节点都大于或等于父节点
- 排列顺序:从上至下,从左至右
- 核心思路
- 将无序的序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆
- 将堆顶数据与末尾数据进行交换,将最大数据“沉”到堆末尾
- 重新调整结构,使其满足大顶堆或小顶堆定义,然后继续交换堆顶数据和堆末尾数据,直到整个堆有序
-
计数排序
- 一种巧妙的只针对特殊数据的排序算法
- 数据要求
- 数据的值固定在一定范围中
- 有大量重复数据
- 核心思路:
- 将数据所有可能出现的值构建成升序数组
- 依次将无序序列中的数据存放到对应数值的升序数组中
- 依次从升序数组中取出数据,完成有序序列
-
桶排序
- 将所有可能出现的值确定在一个范围
- 然后将这个范围划分成多个相同的区间(桶)
- 每个子区间内的数据自排序,再合并
- 尽量减少桶内数据的数量是提高效率的唯一办法
- 时间复杂度(无序序列长度N,一共分M桶)
- N次循环,将所有数据分到对应桶中,记做O(N)
- M次循环,所有桶内数据排序,记做O(M∗(N/M∗log(N/M)))
- 合计O(N∗(log(N/M)+1))
- 当N=M时,即每一个桶只放一个数据时,复杂度为O(N)
-
基数排序
- 将数字0到9作为桶
- 按照低位数字依次放入桶中,然后从左至右,从上至下,依次取出
- 按照高位数字重复上面过程,直至最高位