冒泡排序 是一种简单的交换排序方法;从数列头部(或尾部)开始,进行两两比较,根据大小交换位置,直到最后将最大(小)的数据元素交换到了数列的尾部,然后重复这个过程,直到所有数据元素都排好序。
冒泡排序算法的运作如下:(从后往前)
-
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
-
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
-
针对所有的元素重复以上的步骤,除了最后一个。
-
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
实现代码如下:
// 冒泡排序
function bubble_sort(&$arr){
$len = count($arr);
for ($i=0, $i < $len; $i++) {
for ($j=1; $j < $len-$i; $j++) {
if ($arr[$j-1] > $arr[$j]) {
$temp = $arr[$j-1];
$arr[$j-1] = $arr[$j];
$arr[$j] = $temp;
}
}
}
}
function bubbleSort($arr) {
$cnt = count($arr);
for ($i = 0; $i < $cnt; $i++) {
for ($j = 0; $j < $cnt-$i-1; $j++) {
if ($arr[$j] > $arr[$j+1]) {
$temp = $arr[$j];
$arr[$j] = $arr[$j+1];
$arr[$j+1] = $temp;
}
}
}
return $arr;
}
function maoPaoSort($arr){
if(!is_array($arr)) return false;
$len = count($arr);
if($len <= 1) return $arr;
for($i=0;$i<$len;$i++){
for($j=$len-1;$j>$i;$j--){
if($arr[$j]<$arr[$j-1]){
$temp = $arr[$j-1];
$arr[$j-1] = $arr[$j];
$arr[$j] = $temp;
}
}
}
return $arr;
}
// 测试
$arr = array(10,2,36,14,10,25,23,85,99,45);
$newArr = bubbleSort($arr);
print_r($newArr);
bubble_sort($arr);
print_r($arr);
知识点:php参数前加 & 是什么意思?
加上&的意思是值引用,也就是引用传递,在引用过程中修改参数的数值,能在函数外产生效果。
快速排序 是对冒泡排序的一种改进;它的基本思想是:通过一趟快速排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
该算法是通过分治递归来实现的,其效率很大程度上取决于参考元素的选择,可以选择数组的中间元素,也可以随机得到三个元素,然后选择中间的那个元素(三数中值法)。
另外还有一点,就是当我们在分割时,如果分割出来的子序列的长度很小的话(小于5到20),通常递归的排序的效率就没有诸如插入排序或希尔排序那么快了。因此可以会去判断数组的长度,如果小于10的话,直接用插入排序,而不再递归调用这个快速排序。
冒泡排序算法的运作如下:
设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
<?php
function quickSort($arr){
if(count($arr)>1){
$k=$arr[0];
$x=array();
$y=array();
$_size=count($arr);
for($i=1;$i<$_size;$i++){
if($arr[$i]<=$k){
$x[]=$arr[$i];
}elseif($arr[$i]>$k){
$y[]=$arr[$i];
}
}
$x=quickSort($x);
$y=quickSort($y);
return array_merge($x,array($k),$y);
}else{
return$arr;
}
}
function kuaiSuSort($arr){
if(!is_array($arr)) return false;
if(count($arr)<=1) return $arr;
$pivot = $arr[0];
$big_arr = array();
$small_arr = array();
for ($i=1; $i < count($arr) ; $i++) {
if($arr[$i] >= $pivot){
$big_arr[] = $arr[$i];
}else{
$small_arr[] = $arr[$i];
}
}
$small_arr = kuaiSuSort($small_arr);
$big_arr = kuaiSuSort($big_arr);
return array_merge($small_arr,array($pivot),$big_arr);
}
// 测试
$arr = array(10,2,36,14,10,25,23,85,99,45);
$newArr = quickSort($arr);
print_r($newArr);
?>
选择排序法 是对冒泡排序法的一种改进。选择排序的基本思想是:每一趟在n-i+1(i=1,2,…n-1)个元素中选取最小的元素作为有序序列中第i个元素。基于此思想的算法主要有简单选择排序、树型选择排序和堆排序。
简单选择排序的基本思想:第1趟,在待排序元素[1]~[n]中选出最小的元素,将它与[1]交换;第2趟,在待排序元素[2]~[n]中选出最小的元素,将它与[2]交换;以此类推,第i趟在待排序元素[i]~[n]中选出最小的元素,将它与[i]交换,直到全部排序完毕。
<?php
//选择排序
function SelectSort($arr){
$length = count($arr);
if($length<=1){
return $arr;
}
for($i=0;$i<$length;$i++){
$min = $i;
for($j=$i+1;$j<$length;$j++){
//如果当前最小的还比当前的元素大
if($arr[$min] > $arr[$j]){
$min = $j; //赋值新的最小的
}
}
// 将当前内循环的最小元素放在$i位置上
if($min != $i){
$tmp = $arr[$i];
$arr[$i] = $arr[$min];
$arr[$min] = $tmp;
}
}
return $arr;
}
?>
二分查找(又叫折半查找)适用于有序数列(要求数组已经排好顺序)
<?php
/**
* @param $array 数组
* @param int $low 数组的最小下标
* @param int $high 数组的最大下标
* @return $k 要查询的元素
*/
function bin_search_recursive($array,$k,$low=0,$high=0){
// 判断是否为第一次调用,获取数组元素的数量
if(count($array)!=0 and $high==0){
$high = count($array);
}
if($low <= $high){
$mid = intval(($low+$high)/2); //取$low 与$high的中间值
if($array[$mid] == $k){
return $mid; //如果找到则返回
}elseif($k < $array[$mid]){
return bin_search_recursive($array,$k,$low,$mid-1);
}else{
return bin_search_recursive($array,$k,$mid+1,$high);
}
}
return -1;
}
/*
* //while循环实现二分法查找
*/
function bin_search_while($array,$k){
$low = 0;
$high = count($array)-1;// 使用下标,注意减去1
while($low <= $high){
$mid = intval(($low+$high)/2);
if($array[$mid] == $k){
return $mid;
}elseif($array[$mid] < $k){
$low = $mid+1;
}else{
$high = $mid-1;
}
}
return -1;// 找不到的时候返回-1
}
$arr = array(9,15,34,76,25,5,47,55);
sort($arr);
print_r($arr);
echo "<br />";
// 测试:顺序查找
echo seq_sch($arr,47);
echo "<br />";
//测试:二分查找
echo bin_search_recursive($arr,47);
echo "<br />";
echo bin_search_while($arr,47);
?>
猴子选大王(约瑟夫环问题)
<?php
/**
* @param int $n 开始时的猴子数量
* @param int $m 指定数组,(报到这个数的猴子被淘汰,然后下一个猴子重新从①开始报数)
* @return int 猴子的初始编号
*/
function select_king($n,$m)
{
//猴子的初始数量不能小于2
if ($n<2) { return false; }
//定义一个数组, 数组的值对应猴子的初始编号
$mokey_arr = range(1,$n);
//定义一个变量,记录猴子的报数
$unsetNum=0;
for ($i = 2; $i <=$n*$m ; $i++) //总的循环次数不知道怎么计算,
{
//不过因为循环中设置了return,所以$m*$len效率还可以
foreach ($mokey_arr as $k => $v) {
$unsetNum++; //每到一个猴子, 猴子报数+1
//当猴子的报数等于淘汰的数字时:淘汰猴子(删除数组元素)
//报数归0(下一个猴子从1开始数)
if ($unsetNum == $m) {
// echo "<pre>";//打开注释,可以看到具体的淘汰过程
// print_r($mokey_arr);
unset($mokey_arr[$k]); //淘汰猴子
$unsetNum=0; //报数归零
if (count($mokey_arr)==1) {
//判断数组的长度, 如果只剩一个猴子, 返回它的值
return reset($mokey_arr);
}
}
}
}
}
// 方案一,使用php来模拟这个过程
function getKing($n,$m){
$arr=range(1,$n);
$i= 0;
while(count($arr)!=1){
if(($i+1)%$m==0){
unset($arr[$i]);
}else{
$arr[]=$arr[$i]; //array_push()也是调用这个
unset($arr[$i]);
}
$i++;
}
return $arr[$i];
}
// 方案二
function selectKing($n,$m){
$mokey = range(1, $n);//创建数组,有$n只猴子
$i = 0;
while (count($mokey) >1) {
$i += 1;
$head = array_shift($mokey);//一个个出列最前面的猴子
if ($i % $m !=0) {
//如果不是m的倍数,则把猴子返回尾部,否则就抛掉,也就是出列
array_push($mokey,$head);
}
}
return $mokey[0];//剩下的最后一个就是大王了
}
//方案二,使用数学方法解决
function SelectKingByMath($n,$m) {
$r = 0;
for($i=2; $i<=$n; $i++) {
$r = ($r+$m)%$i;
}
return $r+1;
}
// 测试
print_r(select_king(10,7));
echo '<br/>';
print_r(SelectKing(10,7));
echo '<br/>';
print_r(SelectKingByMath(10,7));
?>