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

搞定PHP面试-常用排序算法及PHP实现

时间:2023-03-29 22:37:56 PHP

常用排序算法及PHP实现全文代码使用PHP7.2语法编写流程图生成工具:https://visualgo.net0。五种基本排序算法比较1.冒泡排序(BubbleSort)冒泡排序是交换排序的一种。它的基本思想是将要排序的记录从后向前(倒序)扫描多次。当发现相邻两条记录的顺序与排序要求的规则不匹配时,交换两条记录。这样,数值较小的记录会逐渐从后往前移动,就像水中的气泡向上浮。算法说明假设有n条记录需要排序,它们的值存放在数组A中。使用冒泡排序的方法,数组A需要扫描n-1次才能完成排序操作。具体过程如下:比较A[n-1]和A[n],如果A[n]$i;$j--){//如果前面的值大于后面的值,交换位置if($arr[$j]<$arr[$j-1]){//交换数组中两个位置的值[$arr[$j],$arr[$j-1]]=[$arr[$j-1],$arr[$j]];}}}}2、选择排序(SelectionSort)选择排序是通过n-i个关键词之间的比较,从n-i+1条记录中选出关键词最小的记录,与第i(1<=i<=n)记录交换。算法说明维护数组中最小的前n个元素的排序序列。每次从剩余的未排序元素中选择最小的元素,将其放在已排序序列的后面,作为序列的第n+1个元素。从一个空序列开始排序工作,直到未排序序列中只剩下一个元素(必须是最大的),就直接放在已排序记录的后面,整个排序就完成了。代码实现/***选择排序*@paramarray$arr*/functionselectionSort(array&$arr):void{$length=count($arr);//外层循环从数组的开头开始,每次循环完成确定一个元素的位置for($i=0;$i<$length-1;$i++){//选中的最小值的索引价值$minIdx=$i;//bitsfrom$i+1开始循环,判断当前选中的元素是否为当前循环的最小值for($j=$i+1;$j<$length;$j++){//如果有是一个小于所选值的值,则替换最小值的索引if($arr[$minIdx]>$arr[$j]){$minIdx=$j;}}//交换数组两个位置的值[$arr[$i],$arr[$minIdx]]=[$arr[$minIdx],$arr[$i]];}}/***选择排序-方法2*@paramarray$arr*/functionselectionSort2(array&$arr):void{$length=count($arr);//外层循环,从数组头部开始,每次循环完成,依次确定数组元素的位置for($i=0;$i<$length;$i++){//开始从$i+1开始循环,依次确定$arr[$i]和$arr[$j]的大小for($j=$i+1;$j<$length;$j++){//如果$arr[$i]大于$arr[$j],交换两个元素的位置if($arr[$i]>$arr[$j]){//交换数组两个位置的值[$arr[$j],$arr[$i]]=[$arr[$i],$arr[$j]];}}}}3.插入排序(InsertionSort)插入排序就是构建一个有序序列,从未排序的数据中选取一个元素,在已排序序列中从后往前扫描,找到对应的位置插入插入排序.在从后往前扫描的过程中,需要将排好序的元素一个一个向后移动,为最新插入的元素提供空间。算法说明对于第一个元素,因为没有比较,所以被认为是一个已经有序的序列。从数组中获取下一个元素,在排序好的元素序列中从后往前扫描,进行判断。如果排序序列的元素大于新元素,则元素向后移动一位。重复步骤(3),直到在排序后的元素中找到小于等于新元素的元素,将新元素插入到该元素的后面。重复步骤(2)~(4)直到排序完成。代码实现/***插入排序*@paramarray$arr*/functioninsertionSort(array&$arr):void{$length=count($arr);//从数组开头开始排序,每完成一个循环,就可以确定一个元素的位置for($i=0;$i<$length-1;$i++){//内层循环从$i+1个元素开始,一个一个向前比较//如果前一个值比自己大,则替换,直到前一个值比自己小,停止循环for($j=$i+1;$j>0;$j--){如果($arr[$j]>=$arr[$j-1]){中断;}[[$arr[$j],$arr[$j-1]]]=[[$arr[$j-1],$arr[$j]]];}}}/***插入排序-方法2*@paramarray$arr*/functioninsertionSort2(array&$arr):void{$length=count($arr);//从数组开头排序,每次循环完成,可以确定一个元素的位置for($i=0;$i<$length-1;$i++){//从第二个开始元素,选择固定位置的值作为参考值$currentVal=$arr[$i+1];//初始键位于所选值的前一个位置$preIdx=$i;//取参考值逐级比较,直到参考值小于之前的值,然后将两个值交换位置while($preIdx>=0&&$currentVal<$arr[$preIdx]){$arr[$preIdx+1]=$arr[$preIdx];$arr[$preIdx]=$currentVal;$preIdx--;}}}4.快速排序(QuickSort)快速排序是将待排序的记录通过一次排序分成两个独立的部分,并且部分记录的关键字均小于另一部分记录的关键字,则可以对两部分记录分别进行排序,以达到对整个序列排序的目的从序列中提取元素并将此元素用作“基线”。对数组扫描一次,将所有小于“base”的元素排在base之前,所有比“base”大的元素都排在base之后。通过递归,将每个子序列分成更小的序列,直到小于基值的元素子序列和大于基值的元素子序列排序完毕。代码实现/***快速排序*@param$arr*/functionquickSort(&$arr):void{$length=count($arr);//如果数组为空,则不需要运行if($length<=1){return;}$middle=$arr[0];//选择一个中间值$left=[];//接收小于中间值$right=[];//接收大于中间值的值//循环比较for($i=1;$i<$length;$i++){if($middle<$arr[$i]){//大于中间值$right[]=$arr[$i];}else{//小于或等于中间值$left[]=$arr[$i];}}//对分割后的左右两边进行递归排序quickSort($left);快速排序($右);$arr=array_merge($left,[$middle],$right);}5.归并排序(MergeSort)算法说明归并是一种典型的序列操作,其工作是将两个或多个有序序列合并为一个有序序列.基于归并的思想,也可以实现排序,称为归并排序。基本方法如下:一开始,将待排序序列中的n个元素看做n个有序子序列(因为只有1个元素的序列总是有序的),每个子序列的长度为1。合并有序子序列成对出现在序列组中,每合并一个理论,序列组中的序列数减半,每个子序列的长度加倍。对加长后的有序子序列重复上述操作,最终得到长度为n的有序序列。这种合并方法也称为简单双向合并排序,其中每个操作将两个排序序列合并为一个排序序列。也可以考虑三路合并或多路合并。代码实现/***MergeSort*@paramarray$arr*@returnarray*/functionmergeSort(array$arr){//计算数组的长度,如果长度不大于1,则不需要排序$长度=计数($arr);如果($length<=1){返回$arr;}//获取数组中间位置的索引$midIdx=floor($length/2);//将数组从中间拆分为左右两部分$left=mergeSort(array_slice($arr,0,$midIdx));$right=mergeSort(array_slice($arr,$midIdx));//合并两部分并同时排序returnmerge($left,$right);}/***合并数组并同时排序*@paramarray$left*@paramarray$right*@returnarray*/functionmerge(array$left,array$right){//分别计算左右数组的长度$lLength=count($left);$rLength=count($right);//左右数组的索引$l=$r=0;$列表=[];//只有当左右数组还没有遍历时,才需要继续遍历//当其中一个数组的元素遍历完成时,说明另一个数组中未遍历的值大于遍历的值while($l<$lLength&&$r<$rLength){//比较$left[$l]和$right[$r],取较小的值加入$lists数组if($left[$l]<$right[$r]){$lists[]=$left[$l];$l++;}别的{$lists[]=$right[$r];$r++;}}//合并$lists和$left和$right中剩余的元素returnarray_merge($lists,array_slice($left,$l),array_slice($right,$r));}/***排序时合并数组-方法二*@paramarray$left*@paramarray$right*@returnarray*/functionmerge2(array$left,array$right){//分别计算左右数组的长度$lLength=count($左);$rLength=count($right);//左右数组的索引$l=$r=0;$列表=[];//只有当左右数组都没有遍历过的时候,才需要继续遍历//当其中一个数组的元素已经遍历完,说明另一个数组中未遍历的值大于thetraverseedvalueswhile($l<$lLength&&$r<$rLength){//比较$left[$l]和$right[$r],取较小的值加入$lists数组中if($left[$l]<$right[$r]){$lists[]=$left[$l];//PHP中unset数组中的元素后,其他元素的key保持不变unset($left[$l]);$l++;}else{$lists[]=$right[$r];取消设置($右[$r]);$r++;}}//合并$lists和$left和$right中剩余的元素returnarray_merge($lists,$left,$right);}/***排序时合并数组-方法3*@paramarray$left*@paramarray$right*@returnarray*/functionmerge3(array$left,array$right){//分别计算左右数组的长度$lLength=count($left);$rLength=count($right);$列表=[];//只有当左右数组都没有遍历过时才需要继续遍历//当其中一个数组的元素遍历完成时,说明另一个数组中未遍历的值大于遍历过的值while($lLength>0&&$rLength>0){//比较$left[$l]和$right[$r],取较小的值加入$lists数组if($left[0]<$right[0]){$lists[]=$left[0];//PHP中unset数组中的元素后,其他元素的键名保持不变unset($left[0]);//重建数组索引,总是让比较的值在第一个$left=array_values($left);$l长度--;}else{$lists[]=$right[0];取消设置($右[0]);$right=array_values($right);$r长度--;}}//合并$lists和$left,$right中剩余的元素returnarray_merge($lists,$left,$right);}