算法练习--归并排序排列题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法练习--归并排序排列题相关的知识,希望对你有一定的参考价值。
背景:
这几天玩的有点多了,代码敲少,今天补一发练习,顺便把前两天做的一个题也贴上。
正题:
1、归并排序
概念(来源百度百科):归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
我的理解,很简单,就是把一个无序数组进行分组,两两组作比较,组别的元素数目为 2^i(i=0,1,2,...,n)的增长。直到最后只有一个完全有序组。
代码(感觉写的十分屎):
<?php function merging_pass($list , $i) { //设置第二个组开始位置 $j = $i; //设置第一个组开始位置 $k = 0; //设置新数组下标 $start = $k; //当发现某一小组没有与之匹配的小组时退出 while($list[$j] != null) { //设置一趟归并中每两组的结束 $j_end = $j+$i; $k_end = $k+$i; while($j<$j_end && $k<$k_end) { if($list[$j] === null || $list[$i] === null) { break; } if($list[$j] < $list[$k]) { $new_list[$start++] = $list[$j++]; } else { $new_list[$start++] = $list[$k++]; } } while($j<$j_end && $list[$j] != null) { $new_list[$start++] = $list[$j++]; } while($k<$k_end && $list[$k] != null) { $new_list[$start++] = $list[$k++]; } $k = $j; $j += $i; } //如果存在单独的小组,直接复制到新数组 while($list[$k] != null) { $new_list[$start++] = $list[$k++]; } print_r($new_list);echo "<br>"; return $new_list; } function merging_sort(&$list) { $count = count($list); $i = 1; while($i < $count) { $list = merging_pass($list , $i); $i *= 2; } } //test $list = array(34,39,31,20,50,10,14,28,17); print_r($list);echo "<br>"; merging_sort($list);
/*
Array ( [0] => 34 [1] => 39 [2] => 31 [3] => 20 [4] => 50 [5] => 10 [6] => 14 [7] => 28 [8] => 17 )
Array ( [0] => 34 [1] => 39 [2] => 20 [3] => 31 [4] => 10 [5] => 50 [6] => 14 [7] => 28 [8] => 17 )
Array ( [0] => 20 [1] => 31 [2] => 34 [3] => 39 [4] => 10 [5] => 14 [6] => 28 [7] => 50 [8] => 17 )
Array ( [0] => 10 [1] => 14 [2] => 20 [3] => 28 [4] => 31 [5] => 34 [6] => 39 [7] => 50 [8] => 17 )
Array ( [0] => 10 [1] => 14 [2] => 17 [3] => 20 [4] => 28 [5] => 31 [6] => 34 [7] => 39 [8] => 50 )
*/
?>
归并排序是一个稳定的的排序,但是相对其他排序,空间复杂度高一些,需要定义一些开始结束标志,和新数组。但是时间复杂度和堆排序是一样的O(nlog2n)。相对而言,归并排序的思想也较好理解。所以自我感觉归并排序是一种很不错的排序方式,不过究竟如何很好的排序,还是要看序列的特征来说啦。(大小排序问题,就告一段落了)
2、字符排序
这是在网上看到的题目,既然看到了,那就练习一下。
思路:大家都知道的,最小序列是abcdefghijkl , 最大序列:lkjihgfedcba ,一共有多少种排发?高中生都知道。。用到排列组合的知识,12!(!表示阶乘)。看看样例 2 ,开始的字母不是a,而是h,那么说明至少这个序列已经排在a,b,c,d,e,f,g开头的序列后边了,那么由第一位我们可以得到 7*11!(计算后将h从总字母表中剔除),第二位是g 那再想想,说明这个序列至少排在以a,b,c,d,e,f,作为第二个位置的序列后边了,此时排名就是 7*11!+6*10!(计算后将g从总字母表中剔除)。 以此类推,最后序列:hgebkflacdji 的排名是7*11!+6*10!+4*9!+1*8!+6*7!+3*6!+5*5!+0*4!+0*3!+1*2!+0*1。
注意:每次单个字母计算后,需从字母表中剔除,因为该字母已选择,序列后面无法再选择该字母。
代码:
<?php /* 获得序列排行。 @param array 所给序列条数和需要排名的序列 @param string 基本序列参考 return array 序列排名 */ function getRankNum($input , $example) { $time = strlen($example); $rank = array_fill(1 , 3 , 1); for($j = 1; $j<=$input[0]; $j++) { $tmp = $example; $start = 0; for($i = $time-1; $i>=1; $i--) { $word = substr($input[$j] , $start++ , 1); $r = strpos($tmp , $word); $rank[$j] += factorial($i)*($r); $tmp = str_replace("$word" , ‘‘ , $tmp); } } return $rank; } /* 计算阶乘。。 @param int 需要计算的数字 return int 阶乘结果 */ function factorial($i) { $result = 1; for(;$i>1;$i--) { $result *= $i; } return $result; } //test $example = ‘abcdefghijkl‘; $input = array(4,‘abcdefghijkl‘,‘hgebkflacdji‘,‘gfkedhjblcia‘,‘abcdefghijlk‘); print_r(getRankNum($input , $example));
//Array ( [1] => 1 [2] => 302715242 [3] => 260726926 [4] => 2 ) ?>
以上是关于算法练习--归并排序排列题的主要内容,如果未能解决你的问题,请参考以下文章