作者前言
大家好,我是阿濠,今篇内容跟大家分享的是排序算法之快速排序,很高兴分享到segmentfault与大家一起学习交流,初次见面请大家多多关照,一起学习进步.
一、快速排序的介绍
基本介绍
快速排序(Quicksort) 是对冒泡排序的一种改进
。
基本思想
1.通过一趟排序
将要排序的数据
`分割成独立的
两部分`
2.一部分
的所有数据
比另外一部分
的所有数据都要小
3.按此方法对这两部分数据
分别进行快速排序
,整个排序过程可以递归进行
,以此达到整个数据变成有序序列
快速排序示意图
二、通过应用示例认识快速排序
有一群小牛,考试成绩分别是{-9,78,0,23,-567,70}
,请从小到大
进行快速排序
,以中间为基准
我们首先先让{-9,78,0,23,-567,70}
变成{-9,-567,0,23,78,70}
static int temp=0;
public static void quickSort(int[] arr,int left, int right) {
int l = left; //左下标
int r = right; //右下标
//pivot中轴值 (左下标+由下标)/2
int pivot = arr[(left + right) / 2];
//while循环的目的是让
//比pivpt小的值放在左边
//比pivpt大的值放在右边
while( l < r){
//从pivot左边进行寻找,若arr[l] > pivot
//则找到比pivot的值大,这时退出循环
while( arr[l] < pivot ){
l += 1;//否则 ++ 后移继续寻找
}
//从pivot右边进行寻找,若arr[r] < pivot
//则找到比pivot的值小,这时退出循环
while( arr[r] > pivot ){
r -= 1;//否则 -- 前移继续寻找
}
//如果l >= r 说明pivot的左右两值已是按照思路
//左边是小于pivot的值
//右边是大于pivot的值
if( l >= r){
break;
}
//此时左边已找到比pivot大的值
//此时右边已找到比pivot小的值
//将它们进行交换
temp=arr[l];
arr[l]=arr[r];
arr[r]=temp;
//若交换完出现与pivot的值则直接后移即可
//比如说有一数组:{2,8,4,4,7,5}
//进行交换后则是:{2,4,4,8,7,5}
//若不进行后移或者前移
//则{2,8,4,4,7,5}交换完后:{2,4,4,8,7,5}
//此时进入第二次while循环 l=1 r=3
//arr[l]<pivot 不满足
//arr[r]>pivot 不满足
//又进行交换:{2,4,4,8,7,5} 变成{2,8,4,4,7,5} 死循环
//如果交换完后,发现这个arr[1] == pivot值相等r--,前移
if(arr[1] == pivot) {
r -= 1;
}
//如果交换完后,发现这个arr[r] == pivot值相等1++,后移
if(arr[r] == pivot) {
l += 1;
}
}
}
运行结果如下:
原数组:[-9, 78, 0, 23, -567, 70]
进行第一次分解后:[-9, -567, 0, 23, 78, 70]
接下来将进行左递归
、右递归
继续分解下去
static int temp=0;
public static void quickSort(int[] arr,int left, int right) {
int l = left; //左下标
int r = right; //右下标
//pivot中轴值 (左下标+由下标)/2
int pivot = arr[(left + right) / 2];
//while循环的目的是让
//比pivpt小的值放在左边
//比pivpt大的值放在右边
while( l < r){
//从pivot左边进行寻找,若arr[l] > pivot
//则找到比pivot的值大,这时退出循环
while( arr[l] < pivot ){
l += 1;//否则 ++ 后移继续寻找
}
//从pivot右边进行寻找,若arr[r] < pivot
//则找到比pivot的值小,这时退出循环
while( arr[r] > pivot ){
r -= 1;//否则 -- 前移继续寻找
}
//如果l >= r 说明pivot的左右两值已是按照思路
//左边是小于pivot的值
//右边是大于pivot的值
if( l >= r){
break;
}
//此时左边已找到比pivot大的值
//此时右边已找到比pivot小的值
//将它们进行交换
temp=arr[l];
arr[l]=arr[r];
arr[r]=temp;
//若交换完出现与pivot的值则直接后移即可
//比如说有一数组:{2,8,4,4,7,5}
//进行交换后则是:{2,4,4,8,7,5}
//若不进行后移或者前移,则{2,8,4,4,7,5}交换完后:{2,4,4,8,7,5}
//此时进入第二次while循环 l=1 r=3
//arr[l]<pivot 不满足
//arr[r]>pivot 不满足
//又进行交换:{2,4,4,8,7,5} 变成{2,8,4,4,7,5} 死循环
//如果交换完后,发现这个arr[1] == pivot值相等r--,前移
if(arr[1] == pivot) {
r -= 1;
}
//如果交换完后,发现这个arr[r] == pivot值相等1++,后移
if(arr[r] == pivot) {
l += 1;
}
}
//如果l == r 必须l++ r-- 为什么呢?
//因为进行第一次分解后[-9, -567, 0, 23, 78, 70] l=1 r=3
//此时在进入while 循环 arr[l]<pivot 满足 ++ l=2
//此时在进入while 循环 arr[r]>pivot 满足 -- r=2
//按图所示这时左递归是组应该是[-9,-567] 对应的是0-1
//中间基数为 0 对应下标是 2
//按图所示这时右递归是组应该是[23,78,70] 对应的是3-5
//所以此时l=2 r=2 则是不对的所以必须需要l++ r--
if( l == r){
l++;
r--;
}
//进行左递归
if( left < r ){
//左递归是组应该是[-9,-567] 对应的是0-1
quickSort(arr,left,r);
}
//进行右递归
if(right > l){
//右递归是组应该是[23,78,70] 对应的是3-5
quickSort(arr,l,right);
}
}
运行结果如下:
原数组:[-9, 78, 0, 23, -567, 70]
进行第一次分解后:[-9, -567, 0, 23, 78, 70]
左递归与右递归进行继续分解后:[-567, -9, 0, 23, 70, 78]
三、复杂度分析
最好的情况
我们发现使用中间数作为基数
,这是最好的情况,时间复杂度:O(nlogn)
最复杂的情况
这其实和冒泡排序类似
,意味着快速排序在最坏情况时间复杂度:O(n^2)
空间复杂度
和归并排序不同,快速排序在每次递归的过程中只需要开辟O(1)的存储空间
来完成交换
操作实现直接对数组的修改
;而递归次数为logn
,所以它的整体空间复杂度完全取决于压堆栈的次数
。
所以空间复杂度是O(logn)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。