排序算法
时间复杂度

归并排序
归并排序的时间复杂度为 量级。
归并排序中有两个核心思想:一是归并,二是分治
归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:
自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法);
自下而上的迭代;
和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是 O(nlogn) 的时间复杂度。代价是需要额外的内存空间。
计数排序
计数排序是一种非基于比较的排序算法,其空间复杂度和时间复杂度均为O(n+k),其中k是整数的范围。基于比较的排序算法时间复杂度最小是O(nlogn)的。该算法于1954年由 Harold H. Seward 提出。
计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
算法步骤
- 花O(n)的时间扫描一下整个序列 A,获取最小值 min 和最大值 max
- 开辟一块新的空间创建新的数组 B,长度为 ( max - min + 1)
- 数组 B 中 index 的元素记录的值是 A 中某元素出现的次数
- 最后输出目标整数序列,具体的逻辑是遍历数组 B,输出相应元素以及对应的个数
堆排序
希尔排序
插入排序
插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
算法步骤
将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)。
快速排序
填坑法
实现对数组的一次划分:partition 函数
partition 算法是快排的核心部分,partition 的作用是在数组中选择一个元素作为参照元素 key ,然后以 key 为参照,将原数组划分为如下两个部分:
位于 key 元素左侧的所有元素都小于 key
位于 key 元素右侧的所有元素都大于 key
下面我们将采用“填坑法”实现 __partition() 函数,"填坑法"的思路是这样的(双指针填坑算法):
首先将参照元素(默认选择数组中的第一个元素为参照元素)从原数组 中取出来,保存在变量 key 中,这样数组 的最左边第一个元素就成了一个空缺的坑位 l
这时,右指针 r 从数组尾部开始查找一个小于 key 的元素,找到后将它取出来,填在坑 l 处,这时右侧就出现了一个坑位:r
然后,左指针 l 从数组首部开始查找一个大于 key 的元素,找到后将它取出来,填在坑 r 处,这时左侧就出现了一个坑位:l
重复上述过程直到 l == r ,最后再将 key 填入坑中即可。
__partition()代码如下:
int __partition(vector<int>& arr, int l, int r) {
int key = arr[l];
while (l < r) {
while (l < r && arr[r] >= key) {
r --;
}
arr[l] = arr[r];
while (l < r && arr[l] <= key) {
l ++;
}
arr[r] = arr[l];
}
arr[l] = key;
return l;
}
再分别对子数组进行划分:分治
一次 partition操作只是将数组分成了大于 key 和小于 key 的两部分,并不能保证整个数组有序。因此接下来就是分别对这两部分进行 partition 划分,递归进行。
时间复杂度
我们发现每次对整个数组进行一次划分需要遍历数组的所有元素,因此一次整体划分的时间复杂度为O(n) , 一共需要进行多少次划分呢?这和参照元素 的选择有关。
最好的情况是每次选择的key 都将当前数组划分为两等分,这样就只需要进行 logn次划分,快排时间复杂度为 .O(nlogn)
最坏的情况是每次选择的 key都是当前序列中的最大或最小元素,这使得每次划分后得到的两部分数组总有一部分为空,另一部分长度为n-1 , 因此这样就需要进行n次划分,快排时间复杂度为 O(n^2).
但快排的平均时间复杂度仍为 .O(nlogn)
空间复杂度:

选择排序
算法步骤
- 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置
- 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
- 重复第二步,直到所有元素均排序完毕。
选择排序
选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。
冒泡排序
桶排序
基数排序
拓扑排序
大数据量排序
参考文章
【基础不牢地动山摇】一遍记住 Java 面试中常用的八种排序算法与代码实现!
买什么数据结构与算法,这里有:动态图解十大经典排序算法(含JAVA代码实现)


浙公网安备 33010602011771号