1 <?php
  2     #查找数组中最小的k个数
  3     
  4     function swap(&$arr, $i, $j) {
  5         $temp = $arr[$i];
  6         $arr[$i] = $arr[$j];
  7         $arr[$j] = $temp;
  8     }
  9 
 10     #第一种方法,使用选择排序直到排好序的部分元素个数为k,效率为O(kn)
 11     function select_sort_k($arr, $k) {
 12         if ($k >= count($arr)) {
 13             return $arr;
 14         }
 15         for ($i = 0; $i < count($arr); $i++) {
 16             $min = $i;
 17             for ($j = $i; $j < count($arr); $j++) {
 18                 if ($arr[$j] < $arr[$min]) {
 19                     $min = $j;
 20                 }
 21             }
 22 
 23             swap($arr, $i, $min);
 24 
 25             if ($i == $k - 1) {
 26                 return array_slice($arr, 0, $k);
 27             }
 28         }
 29     }
 30 
 31     #第二种方法,通过建立最小堆,然后弹出最小元素来实现,效率为O(klogn)
 32 
 33     #调整堆节点
 34     #@param a 待调整数组
 35     #@param start 待调整部分开始坐标
 36     #@param len 待调整数组的长度
 37     function min_heapify(&$a, $start, $len) {
 38         $min = $start;
 39         $left = ($start + 1) * 2 - 1; #左孩子坐标
 40         $right = $left + 1; #右孩子坐标
 41 
 42         if ($left < $len) {
 43             if ($a[$min] > $a[$left]) {
 44                 $min = $left;
 45             }
 46         }
 47 
 48         if ($right < $len) {
 49             if ($a[$min] > $a[$right]) {
 50                 $min = $right;
 51             }
 52         }
 53 
 54         #递归调整节点
 55         if ($min != $start) {
 56             swap($a, $min, $start);
 57             min_heapify($a, $min, $len);
 58         }
 59     }
 60 
 61     #建立最小堆
 62     function build_min_heap(&$a) {
 63         #从最后一个非叶子节点开始调整堆
 64         for ($i = floor(count($a) / 2) - 1; $i >= 0; $i--) {
 65             min_heapify($a, $i, count($a));
 66         }
 67     }
 68 
 69     #利用类似于堆排序的过程查找最小的k个元素
 70     function heap_min_k(&$a, $k) {
 71         build_min_heap($a);
 72         for ($i = 0; $i < $k; $i++) {
 73             #交换首尾元素,并重新调整堆
 74             swap($a, 0, count($a) - 1);
 75             $r[] = array_pop($a);
 76             min_heapify($a, 0, count($a));
 77         }
 78         return $r;
 79     }
 80 
 81     #第三种方法,利用快排的partition来查找
 82     function rand_partition(&$a, $start, $end) {
 83         swap($a, $start, rand($start, $end));
 84         return partition($a, $start, $end);
 85     }
 86 
 87     function partition(&$a, $start, $end) {
 88         $pivot = $start;
 89         $low = $start + 1;
 90         $high = $end;
 91         while ($low < $high) {
 92             while ($low < $high && $a[$low] <= $a[$pivot]) {
 93                 $low++;
 94             }
 95 
 96             #这里表示把所有与pivot相等的元素放到左边
 97             while ($low < $high && $a[$high] > $a[$pivot]) {
 98                 $high--;
 99             }
100 
101             swap($a, $low, $high);
102         }
103 
104         $change = $low;
105         if ($a[$pivot] < $a[$change]) {
106             $change--;
107         }
108         swap($a, $change, $pivot);
109         return $change;
110     }
111 
112     #利用类似于快排的性质来查找k个最小的元素
113     function qsort_k(&$a, $start, $end, &$result, $k) {
114         $q = rand_partition($a, $start, $end);
115         $n = $q - $start + 1; #n表示包括q,小于等于q的元素的总数
116 
117         if ($n == $k) { #如果n = k,说明左边的元素正好足够,全部加入结果集
118             array_splice($result, count($result), 0, array_slice($a, $start, $n));
119         } else if ($n < $k) { #如果n < k, 说明左边的元素不够k个,将左边的元素和q一起归入结果集,并进入递归
120             array_splice($result, count($result), 0, array_slice($a, $start, $n));
121             qsort_k($a, $q + 1, $end, $result, $k - $n);
122         } else {
123             #元素有多,进入左边继续递归
124             qsort_k($a, $start, $q - 1, $result, $k);
125         }
126     }
127 
128     $a = array(5, 7, 3, 2, 4, 6, 9, 0, 1);
129     print_r($a);
130     echo "<br>";
131     print_r(select_sort_k($a, 5));
132     echo "<br>";
133     echo "<br>";
134 
135     $a = array(5, 7, 3, 2, 4, 6, 9, 0, 1);
136     print_r($a);
137     echo "<br>";
138     print_r(heap_min_k($a, 5));
139     echo "<br>";
140     echo "<br>";
141 
142     $a = array(5, 7, 3, 2, 4, 6, 9, 0, 1);
143     print_r($a);
144     echo "<br>";
145     $r = array();
146     qsort_k($a, 0, count($a) - 1, $r, 5);
147     print_r($r);
148 ?>

Array ( [0] => 5 [1] => 7 [2] => 3 [3] => 2 [4] => 4 [5] => 6 [6] => 9 [7] => 0 [8] => 1 ) 
Array ( [0] => 0 [1] => 1 [2] => 2 [3] => 3 [4] => 4 ) 

Array ( [0] => 5 [1] => 7 [2] => 3 [3] => 2 [4] => 4 [5] => 6 [6] => 9 [7] => 0 [8] => 1 ) 
Array ( [0] => 0 [1] => 1 [2] => 2 [3] => 3 [4] => 4 ) 

Array ( [0] => 5 [1] => 7 [2] => 3 [3] => 2 [4] => 4 [5] => 6 [6] => 9 [7] => 0 [8] => 1 ) 
Array ( [0] => 0 [1] => 1 [2] => 3 [3] => 2 [4] => 4 )

posted on 2012-09-28 00:26  ZimZz  阅读(1234)  评论(0编辑  收藏  举报