数据结构与算法--快速排序
简介
基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行
排序图解
从图中可以看出,每进行一次快速排序都需要指定一个值作为基准值,同时还需要左右两个指针不断的扫描,以获取右边比基准值小的数和左边比基准值大的数的下标值,然后交换该两个指针下的值,直到左右指针相遇,交换右指针跟基准值处的下标对应的值
排序原理
- 首先设定一个基准值和两个左右指针,通过基准值将数组分成两个部分
- 将大于或等于基准值的数据放到数组右边,小于基准值的数据放到数组的左边。此时左边部分中各元素都小于或等于基准值,右边部分中各元素都大于或等于基准值
- 然后,将左边和右边的数据进行独立的排序。对于左侧的数组数据,又取一个基准值,将该部分的数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数据做同样的处理
- 重复上述过程,可以看出是一个递归的步骤。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左侧和右侧两个部分的数据排完序后,整个数组的排序也就完成了
代码实现
public void quickSort(int[] arr,int low,int high){
if (low >= high) {
return;
}
//定义两个左右指针和一个存放基准值的变量
int left,right,temp;
//左右指针的值分别为数组左右两端的下标值
left = low;
right = high;
//以数组第一个元素作为基准值
temp = arr[low];
while (left < right) {
//从右往左扫描,找到一个比基准值小的数的下标值
while (arr[right] >= temp && left < right) {
right--;
}
//从左往右扫描,找到一个比基准值大的数的下标值
while (arr[left] <= temp && left < right) {
left++;
}
//如果满足条件则交换
if (left < right) {
exchange(arr,left,right);
}
}
//将基准值的值放到i和j相遇处
exchange(arr,low,right);
//比较基准值左边的数组
quickSort(arr,low,right - 1);
//比较基准值右边的数组
quickSort(arr,right + 1,high);
}
public void exchange(int[] arr, int j, int i) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
时间复杂度分析
快速排序的一次切分从两头开始交替搜索,直到left和right重合,因此,一次切分算法的时间复杂度为O(n),但整个快速排序的时间复杂度和切分的次数相关。
最优情况:每一次切分选择的基准数字刚好将当前序列等分
如果把数组的切分看做是一个树,那么上图就是它的最优情况的图示,共切分了logn次,所以,最优情况下快速排序的时间复杂度为O(nlogn)
最坏情况:每一次切分选择的基准数字是当前序列中最大数或者最小数,这使得每次切分都会有一个子组,那么总共就得切分n次,所以,最坏情况下,快速排序的时间复杂度为O(n2)
快速排序的时间复杂度为O(nlogn)
算法稳定性
快速排序是不稳定,它不满足稳定算法的定义