1.快速排序
快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:
任取待排序元素序列中 的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右 子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
1.1 hoare版本
左边选取key值,用一个keyi记录key值的位置,进入循环,右边先走,右边找小(不小就--),左边找大(不大就++),找到了就相互交换相对位置的数据,如果相遇就退出循环,然后交换相遇的位置和key值的位置,返回排序结束。
1.2挖坑法
基本思想和hoare版本的差不多,就是把key值位置的地方挖成一个坑,然后右边开始走,找小,把当前位置挖成一个新坑,把当前数据放到key值位置的坑位,之后左边开始走找大,找到就把数据放到右边的坑位,当前位置形成新的坑位,循环进行。
1.3前后指针法
基本思想:
用keyi记录key值,就是cur遍历,找到小的,prev就++并和cur位置的数据交换,然后cur++,如此循环反复,当cur>right的时候循环结束,交换prev和keyi的数据,上述代码改变的是prev++不等于cur的时候再交换,不用和自己交换,保持代码的健壮性和可观性。
1.4快排优化
避免有序的情况下,每次都会从右边一直遍历到最左边的key值,然后交换,左边没有数据,把右边整体再进行排序,使得效率退化。
1.4.1 三数取中法选key
将左区间,中间值和右区间作比较,取中间数当做key值换到最左边,然后进行排序。
1.4.2 小区间优化
递归到小的子区间时,因为快排本身需要继续进行左右子区间的递归,会降低效率和浪费内存利用率导致栈溢出,所以当递归到小区间时可以考虑使用插入排序,使得不再递归分割排序,减少递归的次数。
1.5快排的知识点
升序:
1.选取左边为key值,右边先走找小,左边找大,左右相遇的位置的数据一定是比key值小的。
2.选取右边为key值,左边先走找小,左边找大,左右相遇的位置的数据一定是比key值小的。
降序:
3.选取左边为key值,右边先走找大,左边找小,左右相遇的位置的数据一定是比key值大的。
4.选取右边为key值,左边先走找大,左边找小,左右相遇的位置的数据一定是比key值大的。
原因:以一为例
情况一:L遇到R,R停下是因为找到小了,L与R相遇位置的数据一定比key值小,然后交换。
情况二:R遇到L,R找小,没找到就会接着遍历,L的位置一定是上一次和R交换过的数据,二者相遇位置的数据一定是比key值小,然后交换。
1.6快排的非递归实现
这里我利用的是栈的后进先出的特性来实现的,函数调用建立栈帧,栈帧里面存储的核心就是函数的参数,这里就是数组的区间,这里就是不断的将右左区间的数值压栈,先入右区间,再入左区间,出栈顺序就是左区间和右区间了。
循环每走一次,取栈顶区间,单趟排序,右左子区间入栈。
1.7快速排序的特性总结
1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
2. 时间复杂度:O(N*logN)
3. 空间复杂度:O(logN)
4. 稳定性:不稳定
2.归并排序
2.1基本思想:
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有 序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 归并排序核心步骤:
归并排序是需要新开个数组的,防止挪动数据导致覆盖数据。
通过选取中数划分两个左右区间,如果左右区间相等就直接返回,然后开始左右区间递归排序,分完子区间就开始归并,因为分完区间之后每个区间的数据都是有序的,如果左右子区间都没走完,两个左右子区间相比小的就拷贝尾插到新数组了,如果一边走完,就把另一边的数组拷贝尾插到新数组,左右子区间都走完循环就结束了,最后就使用memcpy将数据拷贝到目标数组里。
2.2归并排序的非递归实现
2.3归并排序的特性总结
1. 归并的缺点在于需要O(N)的空间复杂度,思考更多的是解决在磁盘中的外排序问题。
2. 时间复杂度:O(N*logN)
3. 空间复杂度:O(N)
4. 稳定性:稳定