当前位置: 首页 > 后端技术 > PHP

排序算法总结

时间:2023-03-29 23:02:02 PHP

前言各种排序算法不仅是面试中的常见问题,也是各种语言底层常用的。不同场景如何选择最优排序算法?本文总结了各种常用的排序方法,试图进一步理解排序算法注:在下面的描述中,n代表数组的长度,代码会封装一些排序算法中常用的比较,排序算法抽象类定义通过exchange方法,排序算法需要继承这个抽象类实现了抽象方法排序的*@param$array*@returnmixed*/abstractstaticfunctionsort($array);/***元素比较*@param$param1*@param$param2*@returnbool*/publicstaticfunctioncompare($param1,$param2){if($param1>$param2){returntrue;}返回假;}/***元素交换*@param$a*@param$i*@param$j*/publicstaticfunctionexchange(&$a,$i,$j){$temp=$a[$i];$a[$i]=$a[$j];$a[$j]=$温度;}/***打印排序数组*@param$a*/publicstaticfunctionshow($a){var_dump($a);}}选择排序概念step1:找到数组中的最小元素step2:将最小元素与第一个元素交换step3:在数组的其余部分然后找到最小的元素与第二个元素交换……以此类推,直到数组排序算法分析为了在剩余元素中找到最小的元素,需要扫描剩余元素进行比较,数ofcomparisons=(n-1)+(n-2)...+1=n(n-1)/2~n*n/2需要交换代码n-1次才能实现7结束比较,并在7的后面插入8。算法分析插入排序只会将新元素与之前排序的数组进行比较。如果新元素>最后一个元素,则比较结束,选择排序每次都需要遍历剩余数组寻找最小元素,所以一般来说插入排序的效率要高于选择排序。对于已经偏序的数组,会减少插入排序比较的次数,提供插入排序效率。代码实现0;$j--){if(self::compare($array[$j-1],$array[$j])){self::exchange($array,$j-1,$j);}}}返回$array;}}希尔排序的概念对于大规模随机数组插入排序来说是非常慢的,因为它只交换相邻的元素,所以元素需要从数组的一端一点点移动到另一端,如果最小的元素是在数组的末尾,将它移动到正确的位置需要n-1次移动。希尔排序通过交换非相邻元素对数组进行部分排序,提高了插入排序的效率。算法分析希尔排序使用任意区间h的元素是有序的,这样的数组也称为h有序数组。如果h很大,可以将元素移到很远的地方,从而节省移动次数。如果选择h?算法的性能不仅取决于h,还取决于h之间数组的性质。在这里,我不会深究希尔排序比快速排序快得多的事实。阵列越大,优势越大。代码实现=1){for($i=$h;$i<$count;$i++){for($j=$i;$j>=$h&&self::compare($array[$j-$h],$array[$j]);$j-=$h){self::exchange($array,$j,$j-$h);}}$h=$h/3;}返回$array;}}归并排序的概念是对一个数组进行排序,可以分为2个数组分别排序,然后合并两个数组的结果。这也是一个分而治之的算法来分析自顶向下的归并排序:将大数组分成小数组,逐层合并小数组到大数组的自底向上归并排序:合并小数组先合并最后一层的小数组,再合并倒数第二层的小数组。.代码实现=$max)return;$mid=floor(($max+$min)/2);self::sortLoop($a,$min,$mid);self::sortLoop($a,$mid+1,$max);self::merge($a,$min,$mid,$max);//merge}/***合并两个数组*@param$a*@param$min*@param$mid*@param$max*/publicstaticfunctionmerge(&$a,$min,$mid,$max){//将[$min,$mid],[$mid+1,$max]merge$i=$min;$j=$mid+1;//临时数组$temp=$a;对于($k=$min;$k<=$max;$k++){如果($i>$mid)$a[$k]=$temp[$j++];//左边用完了,取右边的数据elseif($j>$max)$a[$k]=$temp[$i++];//右边用完了,取左边的数据elseif(self::compare($temp[$i],$temp[$j]))$a[$k]=$temp[$j++];//左边元素数据大于右边元素数据,取右边否则$a[$k]=$temp[$i++];}}}快速排序的概念快速排序也是采用了分而治之的思想,将数组划分为子数组,如何选择两部分独立排序参考元素,只需选择数组的第一个元素作为referenceelement但是如何遇到一个排序好的逆向数组[5,4,3,1],选择第一个元素,会导致每次排序都不会把数组分成两半,每次排序只能确定的位置参考元素,复杂度变为o(n*n)解:随机选择一个参考元素算法,分析快速排序的优化解由于小数组在快速排序中也是递归排序的,插入排序对于小数组来说更快。修改代码if($min>=$max)return;toif($min+M>=$max){Insert.sort($a,$min,$max);return;},转换参数M和最优值与系统有关,但5之间的任意值-15在大多数情况下是令人满意的熵(shang)对于最优排序,一个所有重复元素的子数组不需要排序,快速排序仍然会把它分成子数组进行排序。当数组中有大量重复元素时,效率会降低。简单的解决方法是将数组分成三部分,分别为>、=、<分割元素的数组元素,返回=分割元素的元素。代码实现=$max)return;$mid=self::getMid($a,$min,$max);self::sortLoop($a,$min,$mid-1);self::sortLoop($a,$mid+1,$max);}/***指针交换方法*@param$a*@param$min*@param$max*@returnint*/publicstaticfunctiongetMid(&$a,$min,$max){$i=$min;$j=$最大值;$v=$a[$min];while($i!=$j){while($i<$j&&$a[$j]>$v){$j--;}while($i<$j&&$a[$i]<=$v){$i++;}if($i<$j){self::exchange($a,$i,$j);}}self::exchange($a,$min,$j);返回$j;}}=$max)return;$lt=$min;$gt=$max;$i=$min+1;$v=$a[$min];while($i<=$gt){$res=$a[$i]-$v;如果($res>0){//如果$i元素>引用元素,将$i与最后一个元素交换self::exchange($a,$i,$gt--);}elseif($res<0){//如果$i元素<基元素$i和最左边的元素交换位置self::exchange($a,$i++,$lt++);}否则{$i++;}}self::sortLoop($a,$min,$i-1);self::sortLoop($a,$gt+1,$max);}}堆排序??概念算法分析代码实现??总结参考:Turingdesignlayers,algorithm(第四版)