php计数排序算法的实现代码(附四个实例代码)
计数排序只适合使用在键的变化不大于元素总数的情况下,它通常用作另一种排序算法(基数排序)的子程序,这样可以有效地处理更大的键。
总之,计数排序是一种稳定的线性时间排序算法。计数排序使用一个额外的数组C ,其中第i个元素是待排序数组 A中值等于 i的元素的个数。然后根据数组C 来将A中的元素排到正确的位置。
通常计数排序算法的实现步骤思路是:
1.找出待排序的数组中最大和最小的元素;
2.统计数组中每个值为i的元素出现的次数,存入数组C的第i项;
3.对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
4.反向填充目标数组:将每个元素i放在新数组的第C[i]项,每放一个元素就将C[i]减去1。
PHP计数排序算法的实现代码示例如下:
- <?php
 - function counting_sort($my_array, $min, $max)
 - {
 - $count = array();
 - for($i = $min; $i <= $max; $i++)
 - {
 - $count[$i] = 0;
 - }
 - foreach($my_array as $number)
 - {
 - $count[$number]++;
 - }
 - $z = 0;
 - for($i = $min; $i <= $max; $i++) {
 - while( $count[$i]-- > 0 ) {
 - $my_array[$z++] = $i;
 - }
 - }
 - return $my_array;
 - }
 - $test_array = array(3, 0, 2, 5, -1, 4, 1);
 - echo "原始数组 :\n";
 - echo implode(', ',$test_array );
 - echo "\n排序后数组\n:";
 - echo implode(', ',counting_sort($test_array, -1, 5)). PHP_EOL;
 
输出:
原始数组 : 3, 0, 2, 5, -1, 4, 1
排序后数组 :-1, 0, 1, 2, 3, 4, 5
下面补充一个例子
1、计数排序只适用于整数在小范围内排序
- <?php
 - $arr = [95,94,91,98,99,90,99,93,91,92];
 - function countSort($arr){
 - $max = $arr[0];
 - $min = $arr[0];
 - for($i=0;$i<count($arr);$i++){
 - if($arr[$i]>$max){
 - $max = $arr[$i];
 - }
 - if($arr[$i] < $min){
 - $min = $arr[$i];
 - }
 - }
 - try{
 - $frequency = new SplFixedArray($max-$min+1);
 - for($i=0;$i<count($arr);$i++){
 - if(emptyempty($frequency[$arr[$i]-$min]))
 - $frequency[$arr[$i]-$min] = 0;
 - $frequency[$arr[$i]-$min] += 1;
 - }
 - $sum = 0;
 - for ($i=0; $i < count($frequency); $i++) {
 - $sum += $frequency[$i];
 - $frequency[$i] = $sum;
 - }
 - $splfixed = new SplFixedArray(count($arr));
 - for($i=(count($arr)-1);$i>=0;$i--){
 - $splfixed[$frequency[$arr[$i]-$min]-1] = $arr[$i];
 - $frequency[$arr[$i]-$min] -= 1;
 - }
 - }catch(RuntimeException $re){
 - echo "RuntimeException: ".$re->getMessage()."\n";
 - }
 - print_r($splfixed->toArray());
 - }
 - countSort($arr);
 - ?>
 
输出
- Array
 - (
 - [0] => 90
 - [1] => 91
 - [2] => 91
 - [3] => 92
 - [4] => 93
 - [5] => 94
 - [6] => 95
 - [7] => 98
 - [8] => 99
 - [9] => 99
 - )
 
2、php计数排序
获取序列中的最小值min和最大值max O(n)
统计min - max之间所有值在序列中的出现次数 O(n)
顺序输出min - max的所有值,次数为0不输出,其余次数为多少就输出多少 O(k) k为数据范围
例如序列为: 2, 4, 6, 9, 4, 8
min = 2, max = 9, n为6,k为8
统计出现次数为
[2 => 1, 3 => 0, 4 => 2, 5 => 0, 6 => 1, 7 => 0, 8 => 1, 9 => 1]
输出结果为
2, 4, 4, 6, 8, 9
很明显,计数排序的复杂度为O(n) + O(k),也就是和数据量和数据范围有关.
若n和k相近,则可认为是O(n)
同时,因为要统计出现次数,如果数据范围过大而数据又很稀疏,造成的空间浪费比较大
- class CountSort
 - {
 - private $originalData = [];
 - private $rangeMap = [];
 - private $resultData = [];
 - public function __construct($original = [])
 - {
 - $this->originalData = $original;
 - }
 - public function sort()
 - {
 - list($min, $max) = $this->calculateDataRange();
 - $this->statisticNumberOfOccurrence($min, $max);
 - $this->resultData = $this->generateResult();
 - return $this->resultData;
 - }
 - protected function calculateDataRange()
 - {
 - $max = null;
 - $min = null;
 - foreach ($this->originalData as $value) {
 - if (!is_null($max)) {
 - if ($value > $max) {
 - $max = $value;
 - }
 - } else {
 - $max = $value;
 - }
 - if (!is_null($min)) {
 - if ($value < $min) {
 - $min = $value;
 - }
 - } else {
 - $min = $value;
 - }
 - }
 - return [$min, $max];
 - }
 - protected function statisticNumberOfOccurrence($min, $max)
 - {
 - for ($i = $min; $i <= $max; $i++) {
 - $this->rangeMap[$i] = 0;
 - }
 - foreach ($this->originalData as $value) {
 - $this->rangeMap[$value]++;
 - }
 - }
 - protected function generateResult()
 - {
 - $result = [];
 - foreach ($this->rangeMap as $key => $value) {
 - if ($value != 0) {
 - for ($i = 0; $i < $value; $i++) {
 - array_push($result, $key);
 - }
 - }
 - }
 - return $result;
 - }
 - }
 - $testData = [2, 3, 4, 3, 10, 30, 20, 15, 10, 12, 33];
 - $countSort = new CountSort($testData);
 - echo '<pre>';
 - var_dump($countSort->sort());
 
输出
- <pre>array(11) {
 - [0]=>
 - int(2)
 - [1]=>
 - int(3)
 - [2]=>
 - int(3)
 - [3]=>
 - int(4)
 - [4]=>
 - int(10)
 - [5]=>
 - int(10)
 - [6]=>
 - int(12)
 - [7]=>
 - int(15)
 - [8]=>
 - int(20)
 - [9]=>
 - int(30)
 - [10]=>
 - int(33)
 - }