快速排序
快排利用的是分治思想。如果要排序数组中下标从 p 到 r 之间的一组数据,选择p 到 r 之间的任意一个数据作为分区点pivot。
遍历 p 到 r 之间的数据,将小于pivot的放到左边,将大于pivot的放到右边,将pivot放到中间。经过这一步骤后数组 p 到 r 之间的数据就被分为了三个部分。数组 p 到 r 之间的数据就被分成了三个部分,前面 p
到 q-1 之间都是小于 pivot 的,中间是 pivot,后面的 q+1 到 r 之间是大于 pivot 的。再根据分治、递归的处理思想,可以用递归排序下标从p 到 q-1之间的数据和下标从q+1到 r 之间的数据,直到区间缩小为 1,就说明所有数据都有序了。
用递推公式将上面的过程写出来:
递推公式:
quickSort(p…r) = quickSort(p…q-1) + quickSort(q+1, r)
终止条件:
p >= r
实现方式
方法1: horea 法:
让 p 从前往后找,找比基准值大的元素,找到就停止
让 q 从后往前找,找比基准值小的元素,找到后停止
将 p 和 q 标记的元素进行交换(为了让前半部分小于后半部分,p 指的是小的)
将基准值和 p 位置的数据进行交换
返回 p
分割的时间复杂度:O(N)
quickSort(int[] arr,int n) {
quickSort_c(arr,0,n-1)
}
// 快速排序递归函数,p r为下标
quick_sort_c(int[] arr,int p,int r) {
if p >= r then return
q = partition(arr, p, r) // 获取分区点的方法
quick_sort_c(arr, p, q-1)
quick_sort_c(arr, q+1, r)
}
关于获取分区的方法,关键在于数据怎么划分,取哪个作为基准值
-
取随机值,比如第一个或最后一个:
每次取随机值数据划分存在极端情况:(递归的时间复杂度:递归的次数*每次递归的时间)
如果每次基准值都可以将区间分割为左右均等的两部分 也是最优情况 O(nlogn)
但是如果划分之后,数据都集中在区间的一侧,也就是数据比较有序 也是最差情况 O(n^2) -
优化:三数取中,使得取得的基准值刚好满足左右两边数据均匀
public int getIndexOfMiddle(int[] arr,int p,int q) {
// 需要注意的是 p 和 right 是索引位置并且没有大小关系的
int pivot