PHP-常用的算法 (一) 四种基本排序
整天说算法算法, 平时反而很少用到这些经典算法, 特此整理一下, 以备不时之需~
一、冒泡排序
基本思想:
对需要排序的数组 从前往后 进行多遍的扫描,当发现相邻的两个数值的次序与排序要求的规则不一致时,就将这两个数值进行交换。这样比较大的数值就将逐渐从前面向后面移动。(反之亦然)
比如 654321, 需要按照从小到大排列, 第一次比较6和5, 因为6>5, 所以6和5交换位置, 变成564321, 然后6继续和4, 3, 2, 1比较, 最后6跑到了尾部,
外层的for循环第一次执行完后变成543216. 第二次执行完432156, 第三次321456 ........ 整个排序完成后变成123456,
数组头部相当于在水底, 数组尾相当于水面, 我们从水面看水底冒泡就是这样的过程, 泡泡是一点一点从小变大的, 离我们最近的时候最大~.
<?php //时间复杂度:最坏情况下是O(n^2),平均情况下也是O(n^2)。
//空间复杂度:O(1)(原地排序,不需要额外空间)
function mysort($arr) { for($i = 0; $i < count($arr); $i++) { for ($j=0; $j< count($arr) - $i - 1; $j++) { if($arr[$j] > $arr[$j+1]) { $temp = $arr[$j]; $arr[$j] = $arr[$j+1]; $arr[$j+1] = $temp ; } } } return $arr; } $arr = array(6,5,4,3,2,1); echo "<pre>"; var_dump(mysort($arr));
二、快速排序
基本思想:
在数组中挑出一个元素(多为第一个)作为标尺,扫描一遍数组将比标尺小的元素排在标尺之前,将所有比标尺大的元素排在标尺之后,通过递归将各子序列分别划分为更小的序列直到所有的序列顺序一致。
//时间复杂度:最坏情况下是O(n^2),平均情况下是O(n log n)。
//空间复杂度:最坏情况下是O(n),平均情况下是O(log n)。
function quick_sort($arr) { //先判断是否需要继续进行 $length = count($arr); if($length <= 1) { return $arr; } //需要排序 //选择一个标尺 -> 通常选择第一个元素 $base_num = $arr[0]; //遍历 除了标尺外的所有元素,按照大小关系放入两个数组内 //初始化两个数组 $left_array = array();//小于标尺的 $right_array = array();//大于标尺的 for($i=1; $i<$length; $i++) { if($base_num > $arr[$i]) { //放入左边数组 $left_array[] = $arr[$i]; } else { //放入右边 $right_array[] = $arr[$i]; } } //再分别对 左边 和 右边的数组进行相同的排序处理方式 //递归调用这个函数,并记录结果 $left_array = quick_sort($left_array); $right_array = quick_sort($right_array); //合并左边 标尺 右边 return array_merge($left_array, array($base_num), $right_array); }
三、选择排序
基本思想:
选择排序法思路: 每次选择一个相应的元素,然后将其放到指定的位置.
比如先找最小值, 放到$arr[0], 再找第二小的值放到$arr[1], 以此类推;
//时间复杂度:最坏情况下是O(n^2),平均情况下也是O(n^2)。
//空间复杂度:O(1)(原地排序,不需要额外空间)
function select_sort($arr) { //实现思路 双重循环完成,外层控制轮数,找到当前轮数的最小值。内层 控制的比较次数 //$i 当前轮数 ,第 $i+1 小, for($i=0, $len=count($arr); $i<$len-1; $i++) { //先假设本轮最小的值的位置 就是 本轮开始的数, 放在$p $p = $i; //$j 是 $i 后边的, 需要比较的数。 for($j=$i+1; $j<$len; $j++) { //$arr[$p] 是 当前已知的最小值, 循环比较, 发先更小的记录下位置, 放在$p if($arr[$p] > $arr[$j]) { $p = $j; } } //本轮结束后, 如果发现 最小值的位置与当前假设的位置$i不同,则位置互换即可 if($p != $i) { $tmp = $arr[$p]; $arr[$p] = $arr[$i]; $arr[$i] = $tmp; } } //返回最终结果 return $arr; }
四、插入排序
基本思想:
第一趟比较前两个数,按大小排序; 第二趟把第三个数据与前两个数从后向前扫描,把第三个数按大小插入到合适的位置;依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程。
//时间复杂度:最坏情况下是O(n^2),平均情况下也是O(n^2)。
//空间复杂度:O(1)(原地排序,不需要额外空间)
function InsertSort(array &$arr){ $count = count($arr); //数组中第一个元素作为一个已经存在的有序表 for($i = 1;$i < $count;$i ++){ $temp = $arr[$i]; //设置哨兵 for($j = $i - 1;$j >= 0 && $arr[$j] > $temp;$j --){ $arr[$j + 1] = $arr[$j]; //记录后移 } $arr[$j + 1] = $temp; //插入到正确的位置 } } $arr = array(9,1,5,8,3,7,4,6,2); InsertSort($arr); echo "<pre>"; var_dump($arr);
- //快速排序(数组排序)
- function quick_sort($array ) {
- if (count($array) <= 1) return $array;
- $key = $array [0];
- $left_arr = array();
- $right_arr = array();
- for ($i= 1; $i<count($array ); $i++){
- if ($array[ $i] <= $key)
- $left_arr [] = $array[$i];
- else
- $right_arr[] = $array[$i ];
- }
- $left_arr = quick_sort($left_arr );
- $right_arr = quick_sort( $right_arr);
- return array_merge($left_arr , array($key), $right_arr);
- }
知止而后有定,定而后能静,静而后能安,安而后能虑,虑而后能得。
所谓诚其意者,毋自欺也。