1 <?php
2 //
3 // +---------------------------------------------------------------------------+4 // | 算法(algorithm),Php演示 |5 // +---------------------------------------------------------------------------+6 // | 这些基本算法的代码,满大街都是,但是我有我的理解。希望你们也有一点收获。 |7 // | 思想是借鉴的,代码是自己敲的,如有不好的地方,接受批评。 |8 // +---------------------------------------------------------------------------+9 // | 以下排序都是从小到大。 |10 // +---------------------------------------------------------------------------+11 // | Author: Chen Hang |12 // +---------------------------------------------------------------------------+
13
14 /*
15 * 冒泡排序其实也分为两种,16 * 第一种是一个值和右边所有值的比较,我姑且称之为“一对多”;17 * 第二种是一个值只和右边相邻的值比较,我姑且称之为“邻值比对”。18 */
19
20 //冒泡排序中的一对多排序
21 function bubblesortMany($arr){
22 for($i=0;$i
23 for($j=$i+1;$j<=count($arr)-1;$j++){
24 //因为i的值不断变大,顺序不断后移,所以先确定左边的最小值。
25 if($arr[$i] > $arr[$j]){
26 $temp = $arr[$i];
27 $arr[$i] = $arr[$j];
28 $arr[$j] = $temp;
29 }
30 }
31 }
32 return $arr;
33 }
34
35 //冒泡之邻值比对
36 function bubblesortNeighbor($arr){
37
38 for($i=0;$i
39 for($j=0;$j
40 //冒泡的邻值比对满足条件必须换值,不断往右移动,此方式只能确定右边最大值。
41 if($arr[$j]>$arr[$j+1]){
42 $temp = $arr[$j];
43 $arr[$j] = $arr[$j+1];
44 $arr[$j+1] = $temp;
45 }
46 }
47 }
48 return $arr;
49 }
50
51 /*
52 * 选择排序简介:选出最小数与第一个位置的数交换,再找出最小的数与第二个位置的数交换,53 * 如此循环到倒数第二个数和最后一个数比较为止。54 * 找出最小的数,也有两种办法,我也姑且称之为“一对多”,“邻值比对”。55 * 冒泡排序的每次比较都有可能换值,选择排序的每次比较都不换值,而是记录下标。56 * 如果冒泡排序很顺溜了,选择排序也该自然的上手吧?57 */
58
59 //选择排序中之一对多
60 function selectsortMany($arr){
61 for($i=0;$i
62 //将最小值的小标保存在$p中,换下标,而不去换值。63 //每次循环的开始,都假定下标是$i的值最小。
64 $p = $i;
65 for($j=$i+1;$j<=count($arr)-1;$j++){
66 //此时同样先确定左边的最小值
67 if($arr[$p]>$arr[$j]){
68 $p = $j;
69 }
70 }
71 //循环结束,才开始换值
72 if($p !== $i){
73 $tmp = $arr[$i];
74 $arr[$i] = $arr[$p];
75 $arr[$p] = $tmp;
76 }
77 }
78 return $arr;
79 }
80
81 //选择排序之邻值比对
82 function selectsortNeighbor($arr){
83 for($i=0;$i
84 $p = $i;
85 //请注意,这里的邻值比对和冒泡的邻值比对逻辑不同,86 //这里挑出最小值
87 for($j=$i;$j
88 if($arr[$p]>$arr[$j+1]){
89 $p = $j +1;
90 }
91 }
92 if($p !== $i){
93 $tmp = $arr[$i];
94 $arr[$i] = $arr[$p];
95 $arr[$p] = $tmp;
96 }
97 }
98 return $arr;
99 }
100
101 /*
102 * 插入排序简介:假定从第二个数开始,第二个数会与第一个数比较;然后103 * 后移,第三个数和第二个数比较,第二个数还是要与第一个数比较;依此类推。104 * 在这种情况下,只能不断的“邻值比对”来确定;如果此时用“一对多”来定最小值105 * 或是最大值,都不能确定之间值情况呀。106 * 我又将这个插入排序按照冒泡排序的两种思维来思考了,我也确实私下认为这是冒泡107 * 排序的另一种。不知道对不对?108 */
109
110 function insertSortNeighbor($arr){
111 for($i=1;$i
112 for($j=$i-1;$j>=0;$j--){
113 if($arr[$j+1]
114 $tmp = $arr[$j+1];
115 $arr[$j+1] = $arr[$j];
116 $arr[$j] = $tmp;
117 }
118 }
119 }
120 return $arr;
121 }
122
123
124 /*
125 * 快排(快速排序)126 * 大方向上分为递归(recursion)实现和迭代(interation)实现。127 * 私下细分为以下四种:128 * 1. 快排递归实现用第一个元素;129 * 2. 快排递归实现用平均数(也叫折半排序);130 * 3. 快排迭代实现用第一个元素;131 * 4. 快排迭代实现用平均数(不推荐)。132 */
133
134 /*
135 * 快排递归实现必须先理解递归,请看下面的递归简单入门程序136 * 递归简单入门程序137 * 在Php中,每调用一个函数,会开辟一个新栈。递归,可以简单的理解为在自己函数138 * 的执行过程中调用了自己,那么同样的会开辟一个新栈,那么递归就是在此栈的基139 * 础上不断往前开辟新栈,然后从后往前收回新栈,在新栈撤回即返回的过程中,才会140 * 执行递归后面的程序,然后一同返回结果。141 * 我在理解递归的时候,用栈图解画出了此程序,从此递归就变得简单了。142 */
143
144 function recursion($str){
145 $str = $str - 1;
146 echo $str,"";
147 if($str > 2){
148 recursion($str);
149 }
150 echo $str,"";
151 }//recursion(5);//4,3,2,2,3,4(用心地理解一下这个结果)152
153
154 //快排递归用第一个元素
155 function quicksortRecursiveOne($arr) {
156 //先判断是否需要继续进行
157 $length = count($arr);
158 if($length <= 1) {
159 return $arr;
160 }
161 //将数组的第一个数来作为基准数
162 $base_num = $arr[0];
163 //小于此基准放入左边,大于或等于放入右边。
164 $left_array = array();
165 $right_array = array();
166 for($i=1; $i
167 if($arr[$i] < $base_num){
168 $left_array[] = $arr[$i];
169 } else {
170 $right_array[] = $arr[$i];
171 }
172 }
173 //再分别对左边和右边的数组进行相同的排序处理方式递归调用这个函数
174 $left_array = quicksortRecursiveOne($left_array);
175 $right_array = quicksortRecursiveOne($right_array);
176 //合并,这个动作发生在撤掉栈返回的时候177 //这个案例的栈图解,私下画了出来,自我感觉十分透彻。178 //个人认为理解这个程序之前,一定要好好理解上面的递归简单入门程序的例子
179 return array_merge($left_array,array($base_num),$right_array);
180 }
181
182 //快排递归用平均数(对半排序)
183 function quicksortRecursiveAvg($arr){
184 //先判断是否需要继续进行
185 $length = count($arr);
186 if($length <= 1) {
187 return $arr;
188 }
189 //对半排序用平均数
190 $arr_avg = array_sum($arr)/count($arr);
191 //选择数组平均数作为基准,小于此基准放入左边,等于放入中间,大于放在右边。192 //这里要注意,必须要将等于单独拿出来,比如你将大于和等于合并一起放入右边,193 //如果有相等的元素,右边的数组会进入无限的循环,你想想是不是。
194 $left_array = array();
195 $right_array = array();
196 for($i=0; $i
197 if($arr_avg > $arr[$i]) {
198 $left_array[] = $arr[$i];
199 }else if($arr_avg = $arr[$i]){
200 $middle_array[] = $arr[$i];
201 }else{
202 $right_array[] = $arr[$i];
203 }
204 }
205 $left_array = quicksortRecursiveAvg($left_array);
206 $right_array = quicksortRecursiveAvg($right_array);
207 return array_merge($left_array,$middle_array,$right_array);
208 }
209
210 //快排迭代用第一个元素211 //这里的迭代举例来说就是:array(1,2,3)迭代为array(array(3),array(2),array(1))212 //推荐看完代码后,自己设置一个简单的数组,画出图解。
213 function quicksortInterationOne($arr){
214 $stock = array($arr);
215 $sort = array();
216 while($stock){
217 $arr = array_pop($stock);
218 if(count($arr) == 1){//看下面就知道,倒序排列,所以最后一个是最小的。
219 $sort[] = $arr[0];//不断地将最小的按顺序放入新的数组,新数组就是从小到大呀。
220 continue;//continue会跳转到while()那里,然后继续往下执行
221 }
222 $base_num = $arr[0];
223 $left_array = array();
224 $right_array = array();
225 for($i=1;$i
226 if($arr[$i] < $base_num)
227 $left_array[] = $arr[$i];
228 else
229 $right_array[] = $arr[$i];
230 }
231 !empty($right_array) && array_push($stock,$right_array);
232 array_push($stock,array($base_num));//记得要将$base_num迭代为数组
233 !empty($left_array) && array_push($stock,$left_array);
234 }
235 return $sort;
236 }
237
238 //快排迭代用平均数(不推荐)
239 function quicksortInterationAvg($arr){
240 $stock = array($arr);
241 $sort = array();
242 while($stock){
243 $arr = array_pop($stock);
244 if(count($arr) == 1){
245 $sort[] = $arr[0];
246 continue;
247 }
248 $base_num = array_sum($arr)/count($arr);
249 $left_array = array();
250 $middle_array = array();
251 $right_array = array();
252 for($i=0;$i
253 if($arr[$i] < $base_num){
254 $left_array[] = $arr[$i];
255 }else if($arr[$i] == $base_num){
256 //如果有重复的元素,比如$middle_array=array(2,2),257 //这里不能转化为array(array(2),array(2)),会陷入无限循环。。
258 $middle_array[] = $arr[$i];
259 }else{
260 $right_array[] = $arr[$i];
261 }
262 }
263 !empty($right_array) && array_push($stock,$right_array);
264 !empty($middle_array) && array_push($stock,$middle_array);
265 !empty($left_array) && array_push($stock,$left_array);
266 }
267 return $sort;
268 }
269
270 //$arr = array(5,5,5,4,4,4,3,3,3);271 // var_dump(quicksortRecursiveAvg($arr));
272
273 /*
274 * 可以优化的地方(Php):275 * 1. 加入flag来判断从小到大或是从大到小,可用性更强。276 * 2. 地址传参,可以节省内存。277 * 3. for($i=0,$num=count($arr);$i
283
284 ?>
285
286