几种排序算法(PHP版)
// 总结一下常见的排序算法。
// 排序分内排序和外排序。
// 内排序:指在排序期间数据对象全部存放在内存的排序。
// 外排序:指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内、外存之间移动的排序。
// 内排序的方法有许多种,按所用策略不同,可归纳为五类:插入排序、选择排序、交换排序、归并排序、分配排序和计数排序。
// 插入排序主要包括直接插入排序,折半插入排序和希尔排序两种;
// 选择排序主要包括直接选择排序和堆排序;
// 交换排序主要包括冒泡排序和快速排序;
// 归并排序主要包括二路归并(常用的归并排序)和自然归并。
// 分配排序主要包括箱排序和基数排序。
// 计数排序就一种。
// 稳定排序:假设在待排序的文件中,存在两个或两个以上的记录具有相同的关键字,在用某种排序法排序后,若这些相同关键字的元素的相对次序仍然不变,则这种排序方法是稳定的。
// 其中冒泡,插入,基数,归并属于稳定排序;选择,快速,希尔,堆属于不稳定排序。
//直接插入法排序
//每次将一个待排序的数据元素,插入到前面已经排好序的数列中的适当的位置,使数列依然有序;直到待排序的数据元素全部插入完成为止。
:六个数12 15 9 20 6 31 24 用直接插入排序,如下图:
思路:
第一步:从给出的六个数中,随便拿出一个数,比如12,形成一个有序的数据序列(一个数当然是有序的数据序列了,不看12之外的数,就当其他的数不存在);
第二步:从剩下的五个数中挑出一个数来,比如15,和刚才的12作比较,12<15,因此,放在12后面,形成数据序列12 15;
第三步:从剩下的四个数中挑出一个数来,比如9,和刚才的有序数据序列12 15作比较,9 < 12 < 15,因此,放在最前面,形成数据序列9 12 15;
第N步,经过这样一个一个的插入并对比,就形成了上图所示的排序结果。在一个元素插入时,首先要和数据序列中最大的元素作比较,如果遇到相同的,则放在相同元素的后面。
特性:
因为要不断的插入,因此直接插入排序一般采用链表结构,属于稳定排序。
function insert_sort($arr) { $len = count($arr); if($len <= 0) return false; for($i=1; $i<$len; $i++) { $flag = $arr[$i]; //待插入的数 for($j=$i-1; $arr[$j]>$flag && $j>=0; $j--) //向前插入合适位置 { $arr[$j+1] = $arr[$j]; //比它大的逐个后移 } $arr[$j+1] = $flag; } return $arr; }
// 折半插入排序
// 折半插入排序(binary insertion sort)是对插入排序算法的一种改进,由于排序算法过程中,就是不断的依次将元素插入前面已排好序的序列中。由于前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。
// 折半插入排序算法的具体操作为:在将一个新元素插入已排好序的数组的过程中,寻找插入点时,将待插入区域的首元素设置为a[low],末元素设置为 a[high],则轮比较时将待插入元素与a[m],其中m=(low+high)/2相比较,如果比参考元素小,则选择a[low]到a[m-1]为新 的插入区域(即high=m-1),否则选择a[m+1]到a[high]为新的插入区域(即low=m+1),如此直至low<=high不成 立,即将此位置之后所有元素后移一位,并将新元素插入a[high+1]。
// 折半插入排序算法是一种稳定的排序算法,比直接插入算法明显减少了关键字之间比较的次数,因此速度比直接插入排序算法快,但记录移动的次数没有变,所以折半插入排序算法的时间复杂度仍然为O(n^2),与直接插入排序算法相同。
$binary_insert_sort = function($arr){ $num = count($arr); //遍历数组 for($i=1;$i<$num;$i++){ //有序数列的起点 $low=0; //有序数列的终点 $high=$i-1; //待插入元素 $t=$arr[$i]; $mid; //循环二分找出插入点 while($low<=$high){ $mid=floor(($low+$high)/2); if($t<$arr[$mid]){ $high=$mid-1; }else{ $low=$mid+1; } } //将有序数组中的大于插入点的数据后移 $j = $i; for($j;$j>$low;$j--){ $arr[$j]=$arr[$j-1]; } //插入数据 $arr[$low]=$t; } return $arr; };
// 希尔排序
// 希尔排序(Shell Sort)又叫做缩小增量排序(diminishing increment sort),是一种很优秀的排序法,算法本身不难理解,也很容易实现,而且它的速度很快。
// 基本思想:
// 先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插入 排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1), 即所有记录放在同一组中进行直接插入排序为止。
// 该方法实质上是一种分组插入方法。插入排序(Insertion Sort)的一个重要的特点是,如果原始数据的大部分元素已经排序,那么插入排序的速度很快(因为需要移动的元素很少)。从这个事实我们可以想到,如果原 始数据只有很少元素,那么排序的速度也很快。--希尔排序就是基于这两点对插入排序作出了改进。
是直接插入排序的改进,例:十个数57 68 59 52 72 28 96 33 24 19用希尔排序,如下图:
思路:
第一步:用排序数字的总数除以2,取奇数得到步长(增量)d1 = 5;
第二步:根据步长d1,将十个数分成五组,如图所示,对这五组各自进行直接插入排序;
第三步:用步长d2继续除以2,取最近的奇数得到步长d2=3;
第四步:根据步长d2,将十个数分成三组,如图所示,对着五组各自进行直接插入排序;
第N步:重复上述分组和排序操作,直到步长变成1,即所有记录放进一个组中排序为止。
特性
由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。
// 希尔排序 // 希尔排序(Shell Sort)又叫做缩小增量排序(diminishing increment sort),是一种很优秀的排序法,算法本身不难理解,也很容易实现,而且它的速度很快。 // 基本思想: // 先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插入 排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1), 即所有记录放在同一组中进行直接插入排序为止。 // 该方法实质上是一种分组插入方法。插入排序(Insertion Sort)的一个重要的特点是,如果原始数据的大部分元素已经排序,那么插入排序的速度很快(因为需要移动的元素很少)。从这个事实我们可以想到,如果原 始数据只有很少元素,那么排序的速度也很快。--希尔排序就是基于这两点对插入排序作出了改进。 $shell_sort = function($arr){ $num = count($arr); $gap = floor($num/2); $flag=true; //按一半的步长分组比对 while($gap>1||$flag) { $flag=false; for($i=0;$i+$gap<$num;$i++){ //比对交换 if($arr[$i]>$arr[$i+$gap]) { $temp = $arr[$i]; $arr[$i] = $arr[$i+$gap]; $arr[$i+$gap] = $temp; $flag=true; } } //步长在减半 if($gap>1){ $gap = floor($gap/2); } } return $arr; };
// 直接选择排序
// 排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n-1个元素,第n个 元素不用选择了,因为只剩下它一个最大的元素了。那么,在一趟选择,如果当前元素比一个元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么 交换后稳定性就被破坏了。比较拗口,举个例子,序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法。时间复杂度是O(n^2)
例:四个数57 68 59 52选择排序:
思路:
第一步:从四个数找到最小的,和初始状态排在第一位的移动互换;
第二步:从剩下三个数中找到最小的,和初始状态排在第二位的移动互换;
第N步:重复上述查找最小和互换的步骤,直到最后一个为止。
特性
举个例子,序列5 8 5 2 9, 我们知道第一遍选择第1个元素5会和2交换,那么原序列中两个5的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法。
function select_sort($arr) { $len = count($arr); if($len <= 0) return false; for($i=0; $i<$len; $i++) { $min = $i; for($j=$i+1; $j<$len; $j++) //记录剩下中最小那的 { if($arr[$j]<$arr[$min]) $min = $j; } if($min != $i) //把当前数与该最小数交换 { $temp = $arr[$min]; $arr[$min] = $arr[$i]; $arr[$i] = $temp; } } return $arr; }
// 堆排序
// 我们知道堆的结构是节点i的孩子为2*i和2*i+1节点,大顶堆要求父节点大于等于其2个子节点,小顶堆要求父节点小于等于其2个子节点。在一个长为n 的序列,堆排序的过程是从第n/2开始和其子节点共3个值选择最大(大顶堆)或者最小(小顶堆),这3个元素之间的选择当然不会破坏稳定性。但当为n /2-1, n/2-2, ...1这些个父节点选择元素时,就会破坏稳定性。有可能第n/2个父节点交换把后面一个元素交换过去了,而第n/2-1个父节点把后面一个相同的元素没 有交换,那么这2个相同的元素之间的稳定性就被破坏了。所以,堆排序不是稳定的排序算法。
//堆排序
关于堆排序,有些复杂,下面举例说明:例:对数列{12,56,23,26,15,86,92,75,65}建立大顶堆(大根堆),则初始堆是?
思路:
分为两个大的过程,第一是建堆过程;
思路:
第一步:根据完全二叉树排列给出的数字,如上图中第一个图;
第二步:因为树是一个单向的过程,叶子结点是无法知道父结点的,因此不能拿叶子结点去和父结点比较;根据结点i,i>=n/2为叶子结点的特性,找出最后一个非叶子结点,然后拿它和它的叶子结点作比较,如果比叶子结点小,则互换(建立的是大顶堆),反之不动。
第三步:紧接着调整n/2 - 1号结点(求出n/2 -1 = 3,也就是23号结点),从图中看出23号结点的两个结点都比它大,那么择优选取一个最大的进行互换。
第N步:按照上述方法,依次互换,最后建立了一个大顶堆。
第二是堆排序过程:
思路:
第一步:首先根据上面建立好的初始堆将根结点92输出,然后用编号最大的结点65替代根结点,断开最大编号结点的指针。
第二步:上一步完成后,检查65结点是否符合大顶堆要求,如果不符合又进行一次建堆的过程(参照第一个过程)。
第N步:按照上述两个步骤,反复操作,就会得到需要的结果。
有可能第n/2个父节点交换把后面一个元素交换过去了,而第n/2-1个父节点把后面一个相同的元素没有交换,那么这2个相同的元素之间的稳定性就被破坏了。所以,堆排序不是稳定的排序算法
function heapSort(&$arr) { #初始化大顶堆 initHeap($arr, 0, count($arr) - 1); //开始交换首尾节点,并每次减少一个末尾节点再调整堆,直到剩下一个元素 for($end = count($arr) - 1; $end > 0; $end--) { $temp = $arr[0]; $arr[0] = $arr[$end]; $arr[$end] = $temp; ajustNodes($arr, 0, $end - 1); } } //初始化最大堆,从最后一个非叶子节点开始,最后一个非叶子节点编号为 数组长度/2 向下取整 function initHeap(&$arr) { $len = count($arr); for($start = floor($len / 2) - 1; $start >= 0; $start--) { ajustNodes($arr, $start, $len - 1); } } //调整节点 //@param $arr 待调整数组 //@param $start 调整的父节点坐标 //@param $end 待调整数组结束节点坐标 function ajustNodes(&$arr, $start, $end) { $maxInx = $start; $len = $end + 1; //待调整部分长度 $leftChildInx = ($start + 1) * 2 - 1; //左孩子坐标 $rightChildInx = ($start + 1) * 2; //右孩子坐标 //如果待调整部分有左孩子 if($leftChildInx + 1 <= $len) { //获取最小节点坐标 if($arr[$maxInx] < $arr[$leftChildInx]) { $maxInx = $leftChildInx; } //如果待调整部分有右子节点 if($rightChildInx + 1 <= $len) { if($arr[$maxInx] < $arr[$rightChildInx]) { $maxInx = $rightChildInx; } } } //交换父节点和最大节点 if($start != $maxInx) { $temp = $arr[$start]; $arr[$start] = $arr[$maxInx]; $arr[$maxInx] = $temp; //如果交换后的子节点还有子节点,继续调整 if(($maxInx + 1) * 2 <= $len) { ajustNodes($arr, $maxInx, $end); } } }
//冒泡排序
//冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,是不用交换的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改 变,所以冒泡排序是一种稳定排序算法。
比较常见的排序算法。举例说明:
思路:
第一步:将倒数第一个和倒数第二个数进行比较,如果小,则互换;
第二步:将倒数第二个和倒数第三个数进行比较,如果小,则互换;
第N步:筛选出最小的一个数,然后从剩下的数中按照上面的方法反复操作,得到需要的序列。
特性
如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并
function bubble_sort($arr) { $len = count($arr); if($len <= 0) return false; for($i=0; $i<$len-1; $i++) { for($j=$i+1; $j<$len-1; $j++) { if($arr[$i] > $arr[$j]) { $t = $arr[$i]; $arr[$i] = $arr[$j]; $arr[$j] = $t; } } } return $arr; }
//快速排序
//快速排序(Quicksort)是对冒泡排序的一种改进。由C. A. R.
Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然
后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序(分治思想)是对冒泡排序的一种改进,思想:从数列中挑出一个元素,称为 "基准"(pivot);重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分割 结束之后,该基准就处于数列的中间位置。这个称为分割(partition)操作;递归地(recursive)把小于基准值元素的子数列和大于基准值元 素的子数列排序。
思路:
第一步:从给出的数列中找到一个基准,如图中的57,左指针指向57,右指针指向最后一个元素;
第二步:对左指针与右指针指向的元素作对比,右指针指向的元素19比左指针指向的元素57小(基准),互换位置;
第三步:左指针右移一个后跟右指针对比,68>57,因此互换;
第N步:按照上述的步骤经过指针的不断移动和元素的对比互换,最后得出第一个以57为中心的序列(左侧小于57,右侧大于57);接下来利用递归分别对57前后的进行排序。
特性
上面右侧的动态图很好的说明了快速排序的思路,快速排序是一个不稳定的排序算法。
function quick_sort($arr) { $len = count($arr); if($len <= 1) return $arr; $mid = $arr[0]; //以此数为基准拆分为两个数组 $l = $r = array(); for($i=1; $i<$len; $i++) { if($arr[$i]<$mid) $l[] = $arr[$i]; else $r[] = $arr[$i]; } $l = quick_sort($l); $r = quick_sort($r); return array_merge($l, array($mid), $r); }
//二路归并排序
//归并排序是把序列递归地分成短序列,递归出口是短序列只有1个元素(认为直接有序)或者2个序列(1次比较和交换),然后把各个有序的段序列合并成一个有 序的长序列,不断合并直到原序列全部排好序。可以发现,在1个或2个元素时,1个元素不会交换,2个元素如果大小相等也没有人故意交换,这不会破坏稳定 性。那么,在短的有序序列合并的过程中,稳定是是否受到破坏?没有,合并过程中我们可以保证如果两个当前元素相等时,我们把处在前面的序列的元素保存在结 果序列的前面,这样就保证了稳定性。所以,归并排序也是稳定的排序算法
// 第一步:把待排序的每一个元素看做一个有序表(则由n个有序表),通过两两合并,生成⌊n/2⌋个长度为2(最后一个表的长度可能小于2)的有序表。
// 第二步:每组内部进行排序;
// 第三步:两组两组进行归并,将两个指针分别定为两组最小的两个数,然后进行比较,小的挑出来,指针后移,继续比较。
// 第N步:进过上述不断的归并和比较,最终得出一个正确的序列。
该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
思路:
第一步:把待排序的每一个元素看做一个有序表(则由n个有序表),通过两两合并,生成⌊n/2⌋个长度为2(最后一个表的长度可能小于2)的有序表。
第二步:每组内部进行排序;
第三步:两组两组进行归并,将两个指针分别定为两组最小的两个数,然后进行比较,小的挑出来,指针后移,继续比较。
第N步:进过上述不断的归并和比较,最终得出一个正确的序列。
归并排序是稳定的排序算法
function merge(&$arr,$start,$mid,$end) { $i = $start; $j = $mid+1; $k = 0; $ary = array(); while($i <= $mid && $j <= $end) { if($arr[$i] <= $arr[$j]) { $ary[$k++] = $arr[$i++]; } else { $ary[$k++] = $arr[$j++]; } } while($i <= $mid) { $ary[$k++] = $arr[$i++]; } while($j <= $end) { $ary[$k++] = $arr[$j++]; } for($i = 0 ;$i < $k;$i++) { $arr[$i + $start] = $ary[$i]; } } function merge_sort(&$array,$low,$high) { if($low < $high) { // 任何递归都要有边界,否则就是死循环 $mid = floor(($low+$high) / 2); merge_sort($array,$low,$mid); merge_sort($array,$mid+1,$high); merge($array,$low,$mid,$high); } else { return ;// 这里其实可以不写,php内部默认都会自动加return的 } }
排序算法复杂度:
(1)平方阶(O(n2))排序
一般称为简单排序,例如直接插入、直接选择和冒泡排序;
(2)线性对数阶(O(nlgn))排序
如快速、堆和归并排序;
(3)O(n1+£)阶排序
£是介于0和1之间的常数,即0<£<1,如希尔排序;
(4)线性阶(O(n))排序
如桶、箱和基数排序。
不同条件下,排序方法的选择
(1)若n较小(如n≤50),可采用直接插入或直接选择排序。
当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接插人,应选直接选择排序为宜。
(2)若文件初始状态基本有序(指正序),则应选用直接插人、冒泡或随机的快速排序为宜;
(3)若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。
快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;
堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。这两种排序都是不稳定的。
若要求排序稳定,则可选用归并排序。但本章介绍的从单个记录起进行两两归并的
排序算法并不值得提倡,通常可以将它和直接插入排序结合在一起使用。先利用直接插入排序求得较长的有序子文件,然后再两两归并之。因为直接插入排序是稳定
的,所以改进后的归并排序仍是稳定的。 4)在基于比较的排序方法中,每次比较两个关键字的大小之后,仅仅出现两种可能的转移,因此可以用一棵二叉树来描述比较判定过程。
当文件的n个关键字随机分布时,任何借助于"比较"的排序算法,至少需要O(nlgn)的时间。
各类算法的比较
1000个随机数测试结果:
直接插入排序:
时间:0.22043514251709
二分插入排序:
时间:0.17451214790344
哈希插入排序:
时间:0.32956099510193
选择排序:
时间:0.27549505233765
堆排序:
时间:0.055191993713379
冒泡排序:
时间:0.61164093017578
快速排序:
时间:0.02063512802124
归并排序:
时间:0.031260013580322
参考
http://blog.csdn.net/bjyfb/article/details/7513509
http://www.cnblogs.com/xkfz007/archive/2012/07/01/2572017.html
<?php //直接插入法排序 $InsertSort = function($arr){ $num = count($arr); // 遍历数组 for ($i = 1;$i < $num; $i++) { // 获得当前值 $iTemp = $arr[$i]; // 获得当前值的前一个位置 $iPos = $i - 1; // 如果当前值小于前一个值切未到数组开始位置 while (($iPos >= 0) && ($iTemp < $arr[$iPos])) { // 把前一个的值往后放一位 $arr[$iPos + 1] = $arr[$iPos]; // 位置递减 $iPos--; } $arr[$iPos+1] = $iTemp; } return $arr; }; // 折半插入排序 $binary_insert_sort = function($arr){ $num = count($arr); //遍历数组 for($i=1;$i<$num;$i++){ //有序数列的起点 $low=0; //有序数列的终点 $high=$i-1; //待插入元素 $t=$arr[$i]; $mid; //循环二分找出插入点 while($low<=$high){ $mid=floor(($low+$high)/2); if($t<$arr[$mid]){ $high=$mid-1; }else{ $low=$mid+1; } } //将有序数组中的大于插入点的数据后移 $j = $i; for($j;$j>$low;$j--){ $arr[$j]=$arr[$j-1]; } //插入数据 $arr[$low]=$t; } return $arr; }; // 希尔排序 $shell_sort = function($arr){ $num = count($arr); $gap = floor($num/2); $flag=true; //按一半的步长分组比对 while($gap>1||$flag) { $flag=false; for($i=0;$i+$gap<$num;$i++){ //比对交换 if($arr[$i]>$arr[$i+$gap]) { $temp = $arr[$i]; $arr[$i] = $arr[$i+$gap]; $arr[$i+$gap] = $temp; $flag=true; } } //步长在减半 if($gap>1){ $gap = floor($gap/2); } } return $arr; }; // 直接选择排序 $select_sort = function($arr) { $num = count($arr); for($i=0;$i<$num-1;$i++) { //取得最小值 $min=$arr[$i]; $index=$i; for($j=$i+1;$j<$num;$j++){ if($arr[$j]<$min) { $min=$arr[$j]; $index=$j; } } //交换 $temp = $arr[$i]; $arr[$i] = $arr[$index]; $arr[$index] = $temp; } return $arr; }; // 堆排序 function heapSort(&$arr) { #初始化大顶堆 initHeap($arr, 0, count($arr) - 1); //开始交换首尾节点,并每次减少一个末尾节点再调整堆,直到剩下一个元素 for($end = count($arr) - 1; $end > 0; $end--) { $temp = $arr[0]; $arr[0] = $arr[$end]; $arr[$end] = $temp; ajustNodes($arr, 0, $end - 1); } } //初始化最大堆,从最后一个非叶子节点开始,最后一个非叶子节点编号为 数组长度/2 向下取整 function initHeap(&$arr) { $len = count($arr); for($start = floor($len / 2) - 1; $start >= 0; $start--) { ajustNodes($arr, $start, $len - 1); } } //调整节点 //@param $arr 待调整数组 //@param $start 调整的父节点坐标 //@param $end 待调整数组结束节点坐标 function ajustNodes(&$arr, $start, $end) { $maxInx = $start; $len = $end + 1; //待调整部分长度 $leftChildInx = ($start + 1) * 2 - 1; //左孩子坐标 $rightChildInx = ($start + 1) * 2; //右孩子坐标 //如果待调整部分有左孩子 if($leftChildInx + 1 <= $len) { //获取最小节点坐标 if($arr[$maxInx] < $arr[$leftChildInx]) { $maxInx = $leftChildInx; } //如果待调整部分有右子节点 if($rightChildInx + 1 <= $len) { if($arr[$maxInx] < $arr[$rightChildInx]) { $maxInx = $rightChildInx; } } } //交换父节点和最大节点 if($start != $maxInx) { $temp = $arr[$start]; $arr[$start] = $arr[$maxInx]; $arr[$maxInx] = $temp; //如果交换后的子节点还有子节点,继续调整 if(($maxInx + 1) * 2 <= $len) { ajustNodes($arr, $maxInx, $end); } } } //冒泡排序 $BubbleSort = function($arr) { // 获得数组总长度 $num = count($arr); // 正向遍历数组 for ($i = 1; $i < $num; $i++) { // 反向遍历 for ($j = $num - 1; $j >= $i ; $j--) { // 相邻两个数比较 if ($arr[$j] < $arr[$j-1]) { // 暂存较小的数 $iTemp = $arr[$j-1]; // 把较大的放前面 $arr[$j-1] = $arr[$j]; // 较小的放后面 $arr[$j] = $iTemp; } } } return $arr; }; $bubble_sort2 = function($a) { $n = count($a); $flag=true; for($i=$n-1;$i>0 && $flag;$i--){ $flag=false; for($j=0;$j<$i;$j++){ //把最大的换到后面 if($a[$j]>$a[$j+1]){ $iTemp = $a[$j]; $a[$j] = $a[$j+1]; $a[$j+1] = $iTemp; $flag=true; } } } return $a; }; //快速排序 function quick_sort($arr) { $len = count($arr); if($len <= 1) return $arr; $mid = $arr[0]; //以此数为基准拆分为两个数组 $l = $r = array(); for($i=1; $i<$len; $i++) { if($arr[$i]<$mid) $l[] = $arr[$i]; else $r[] = $arr[$i]; } $l = quick_sort($l); $r = quick_sort($r); return array_merge($l, array($mid), $r); } //二路归并排序 function merge(&$arr,$start,$mid,$end) { $i = $start; $j = $mid+1; $k = 0; $ary = array(); while($i <= $mid && $j <= $end) { if($arr[$i] <= $arr[$j]) { $ary[$k++] = $arr[$i++]; } else { $ary[$k++] = $arr[$j++]; } } while($i <= $mid) { $ary[$k++] = $arr[$i++]; } while($j <= $end) { $ary[$k++] = $arr[$j++]; } for($i = 0 ;$i < $k;$i++) { $arr[$i + $start] = $ary[$i]; } } function merge_sort(&$array,$low,$high) { if($low < $high) { // 任何递归都要有边界,否则就是死循环 $mid = floor(($low+$high) / 2); merge_sort($array,$low,$mid); merge_sort($array,$mid+1,$high); merge($array,$low,$mid,$high); } else { return ;// 这里其实可以不写,php内部默认都会自动加return的 } } echo '1000个随机数:','<br/>'; for($i=0;$i<1000;$i++){ $array[] = rand(); } foreach($array as $val){ echo $val,','; } echo '<br/>'; echo '直接插入排序:','<br/>'; $b = microtime(true); foreach($InsertSort($array) as $val){ echo $val,','; } $e = microtime(true); echo '<br/>'; echo '时间:',$e-$b,'<br/>'; echo '二分插入排序:','<br/>'; $b = microtime(true); foreach($binary_insert_sort($array) as $val){ echo $val,','; } $e = microtime(true); echo '<br/>'; echo '时间:',$e-$b,'<br/>'; echo '哈希插入排序:','<br/>'; $b = microtime(true); foreach($shell_sort($array) as $val){ echo $val,','; } $e = microtime(true); echo '<br/>'; echo '时间:',$e-$b,'<br/>'; echo '选择排序:','<br/>'; $b = microtime(true); foreach($select_sort($array) as $val){ echo $val,','; } $e = microtime(true); echo '<br/>'; echo '时间:',$e-$b,'<br/>'; echo '堆排序:','<br/>'; $arrayT = $array; $b = microtime(true); heapSort($arrayT); foreach($arrayT as $val){ echo $val,','; } $e = microtime(true); echo '<br/>'; echo '时间:',$e-$b,'<br/>'; echo '冒泡排序:','<br/>'; $b = microtime(true); foreach($bubble_sort2($array) as $val){ echo $val,','; } $e = microtime(true); echo '<br/>'; echo '时间:',$e-$b,'<br/>'; echo '快速排序:','<br/>'; $b = microtime(true); foreach(quick_sort($array) as $val){ echo $val,','; } $e = microtime(true); echo '<br/>'; echo '时间:',$e-$b,'<br/>'; echo '归并排序:','<br/>'; $arrayG = $array; $b = microtime(true); merge_sort($arrayG,0,count($arrayG)-1); foreach($arrayG as $val){ echo $val,','; } $e = microtime(true); echo '<br/>'; echo '时间:',$e-$b,'<br/>';
posted on 2012-05-28 17:15 kudosharry 阅读(590) 评论(0) 编辑 收藏 举报