1.快速排序的概念
随机找出一个数(通常就拿数组的第一个数就行),把它插入一个位置,使得它左边的数都比它小,右边的数都比它大,这样就将一个数组分成了两个子数组,然后在按照同样的方法把子数组分成更小的子数组,直到不能分解为止。用比较通俗的话:挖坑填数+分而治之。
2.图解分析
取第一个数作为基准数,这是low=0,high=8,target=arr[0]=12,由于已经将arr[0]保存到变量target中,可以理解成在数组arr[0]上挖了一个坑,那就需要将这个坑填上,从high=8开始向后扫描,遇到一个比target小的数,arr[8]就符合,用arr[8]这个数将arr[0]这个坑填上,arr[0]=arr[8];arr[8]又出现了坑,就需要从low=1开始由左向右扫描,找一个比target=12大的数,arr[1]就符合,将arr[8]的这个坑用arr[1]填上,arr[8]=arr[1];arr[1]出现了坑,需要从high=7开始向左扫描,找一个比target=12小的数,arr[7]填上arr[1],arr[1] = arr[7];在由low=2开始向右扫描,找一个比target=12大的数,arr[2]填上arr[7],arr[7]=arr[2]......直到high=low,将目标数填上最后的这个坑,arr[high]=target,这样就变成了
用target=12将数组分成了两个子数组,分别对这两个子数组进行上面的操作。
3.代码实现
//找到要插入的位置
function findPos(&$arr, $low, $high) {
$target = $arr[$low]; // 将目标数存起来
while ($low < $high) {
//从右向左找小于target的数
while ($low < $high && $arr[$high] >= $target) {
$high--;
}
$arr[$low] = $arr[$high]; //将arr[high]填到arr[low]中
//从左向右找大于target的数
while ($low < $high && $arr[$low] <= $target) {
$low++;
}
$arr[$high] = $arr[$low]; //将arr[low]填到arr[high]中
}
$arr[$high] = $target; //此时low=high,将目标数填入这个坑中
return $high;
}
function quitSort(&$arr,$low,$high){
$pos = findPos($arr, $low, $high);
if ($low<$pos-1){
quitSort($arr,$low,$pos-1);
}
if ($pos+1 < $high){
quitSort($arr,$pos+1,$high);
}
}
$arr = [12,56,98,32,16,34,2,9,1];
$len = count($arr);
quitSort($arr,0,$len-1);
dump($arr);
4.效果展示
5.效率分析
①快排的一个关键因素是选好枢轴,它进行一趟排序后,枢轴元素在表中的位置被唯一确定下来,且枢轴元素将待排序列分成两个子序列,左边的序列中的元素都比 枢轴元素小,右边的序列都比枢轴元素大。然后,分别在左右序列中选择枢轴元素再开始排序,因而,快排中包含了递归。
②当待排的元素初始有序时,快排的性能大大地下降。因为此时枢轴划分的子序列严重地不对称(一般选择第一个元素作为枢轴记录),快排退化为冒泡排序。
③快排是不稳定的,因为在排序过程中,设置了两个指针 low 和 high 。首先从high 开始自减,寻找第一个比枢轴小的元素,并将之与枢轴记录进行交换,这种跳跃式的交换可能会造成元素的相对位置的改变。
④对于快排而言,元素的初始序列与排序的趟数和比较次数是有关的。但是,平均情况下,对于内部排序而言,快排的性能是最好。平均时间复杂度为 O(n^2),空间复杂度为O(logn)。
效果展示来自http://blog.jobbole.com/11745/