十大排序算法之快速排序(4)
快速排序及其优化
基础快速排序
/**
* 基础快速排序
* @param $sortData
* @return array
*/
function quickSort($sortData){
$count = count($sortData);
if ($count <= 1) return $sortData;
$middle = selectPivot($sortData);
$leftArray = [];
$rightArray = [];
for ($i = 1; $i < $count; $i++){
if ($sortData[$i] > $middle){
$rightArray[] = $sortData[$i];
} else {
$leftArray[] = $sortData[$i];
}
}
$leftArray = quickSort($leftArray);
$leftArray[] = $middle;
$rightArray = quickSort($rightArray);
return array_merge($leftArray, $rightArray);
}
/**
* 方法(1):固定位置
* 思想:取序列的第一个或最后一个元素作为基准
*
* 基准位1:
*/
function selectPivot($sortData){
return $sortData[0];
}
function getSortData($number = 0){
$sortData = [];
for ($i = 0; $i < $number; $i++){
$sortData[] = rand(0, 1000000);
}
return $sortData;
}
$stime = microtime(true); #获取程序开始执行的时间
$data = quickSort(getSortData(10000));
echo implode(',', $data);
$etime = microtime(true); #获取程序执行结束的时间
$total = $etime - $stime; #计算差值
基准优化方式
对于分治算法,当每次划分时,算法若都能分成两个等长的子序列时,那么分治算法效率会达到最大。也就是说,基准的选择是很重要的。选择基准的方式决定了两个分割后两个子序列的长度,进而对整个算法的效率产生决定性影响。
最理想的方法是,选择的基准恰好能把待排序序列分成两个等长的子序列
优化1:随机选取基准
引入的原因:在待排序列是部分有序时,固定选取枢轴使快排效率底下,要缓解这种情况,就引入了随机选取枢轴
思想:取待排序列中任意一个元素作为基准
function selectPivot($sortData){
return $sortData[rand(0, count($sortData) - 1)];
}
优化2:三数取中(median-of-three)
引入的原因:虽然随机选取枢轴时,减少出现不好分割的几率,但是还是最坏情况下还是O(n^2),要缓解这种情况,就引入了三数取中选取枢轴
分析:最佳的划分是将待排序的序列分成等长的子序列,最佳的状态我们可以使用序列的中间的值,也就是第N/2个数。可是,这很难算出来,并且会明显减慢快速排序的速度。这样的中值的估计可以通过随机选取三个元素并用它们的中值作为枢纽元而得到。事实上,随机性并没有多大的帮助,因此一般的做法是使用左端、右端和中心位置上的三个元素的中值作为枢纽元。显然使用三数中值分割法消除了预排序输入的不好情形,并且减少快排大约14%的比较次数
举例:待排序序列为:8 1 4 9 6 3 5 2 7 0
左边为:8,右边为0,中间为6.
我们这里取三个数排序后,中间那个数作为枢轴,则枢轴为6
注意:在选取中轴值时,可以从由左中右三个中选取扩大到五个元素中或者更多元素中选取,一般的,会有(2t+1)平均分区法(median-of-(2t+1),三平均分区法英文为median-of-three)。
具体思想:对待排序序列中low、mid、high三个位置上数据进行排序,取他们中间的那个数据作为枢轴,并用0下标元素存储枢轴。
function selectPivot($sortData){
$count = count($sortData);
$first = $sortData[0];
$end = $sortData[$count - 1];
$middle = $sortData[intval($count/ 2)];
if($first < $middle){
$tmp = $first;
$first = $middle;
$middle = $tmp;
}
if($first < $end){
$tmp = $first;
$first = $end;
$end = $tmp;
}
if($middle < $end){
$tmp = $middle;
$middle = $end;
$end = $tmp;
}
return $middle;
}
其他优化方式
优化1、当待排序序列的长度分割到一定大小后,使用插入排序。
优化2、在一次分割结束后,可以把与Key相等的元素聚在一起,继续下次分割时,不用再对与key相等元素分割
分类:
base.算法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2018-03-03 PHP常见概念混淆(一)之PHP数组