PHP数据结构(二十一)——希尔排序
(原创内容,转载请注明来源,谢谢)
一、概述
希尔排序,又称缩小增量排序,也属于插入排序类方法,时间上有较大改进。前面叙述的插入排序方法的时间复杂度都是O(n2),当待排序记录都是正序时,时间复杂度提高到O(n)。
希尔排序的基本思想是:先将整个待排记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录基本有序时,再对全体进行一次插入排序。
二、算法
希尔排序实质上就是跳跃版的直接插入排序,其每次都设定一个不同的增量,如第一次增量是5、第二次增量是3,进行两轮插入排序后,最后再从头进行一次直接插入排序。
以第一次增量为5,第二次增量为3,数组长度为10举例,说明希尔排序算法。
1)把数组进行分组,因为增量是5,因此把下标048、159、26、37分别划分到各组,对每组依次进行直接插入排序,排序后每一组包含的数组下标还是原先的那几个数字(如048组进行插入排序,假设0对应的值大于4,则排序后下标变为408,不占用其他组的下标),排序后数组部分有序,此时称为完成一轮希尔排序。
2)以0369、147、258的下标值分组,分别对这三组值进行插入排序。此时称为完成第二轮希尔排序。
3)将前两轮排序后的数组,从头开始进行插入排序。
4)以此为拓展,可以输入一组增量数组,按照增量的值,依次进行分组的插入排序,最后再进行一次增量为1的插入排序。
三、实现源码
//希尔排序 输入的第一个参数为增量数组,不用输入最终的增量1
publicfunction shellInsertSort(array $arrIncr, array $arr = array()){
//如果增量数组长度小于1,直接调用直接插入排序即可
if(1> count($arrIncr)){
return$this->directInsertSort($arr);
}
$arr= $this->_checkNeedSort($arr);
if(!$arr){
return$arr;
}
//循环调用增量数组中的增量
foreach($arrIncras $incr){
//如果增量大于或等于数组长度,则直接取下一个增量
for($i=$incr;$i<count($arr);$i++){
$tmp= $arr[$i];
//以增量$incr的序列组成数组,同样假设前i-1个数有序,对第i个进插入排序
for($j=$i-$incr;$j>=0&&$tmp<$arr[$j];$j=$j-$incr){
$arr[$j+$incr]= $arr[$j];
}
$arr[$j+$incr]= $tmp;
}
}
//最后一组数组,调用直接插入排序,步长为1
$arr= $this->directInsertSort($arr);
return$arr;
}
四、评价
希尔排序的好坏,和选定的因子有非常大的关系,目前尚无定论哪种最好。但是经过大量的推导,当增量函数dlta[k]=2t-k+1-1时,时间复杂度为O(n3/2),其中t为排序的趟数,k的范围是1<=k<=t<=log2(n+1)(向下取整)。
增量函数的建议方法:
1)1,2,3,5,9…dlta[k]=2t-k+1 (0<=k<=t<= log2(n-1)(向下取整))
2)1,4,13,40…dlta[k]=(3t-k-1)/2 (0<=k<=t<= log2(2n+1)(向下取整))
增量函数要求:应使增量序列中的值没有除1以外的公因子,最终的增量值必须是1。
——written by linhxx 2017.07.18
相关阅读: