递推算法
通过已知条件,利用特定关系得到中间推论,直至得到结果;(分顺推,逆推)
ps:斐波那契数列,1 1 2 3 5 8 13 。。。得到第n位数;
规律:首位1,二位1,三位开始前两数和;
function feibo($n)
{
if($n == 1 || $n == 2)
return 1;
$f[1] = 1;
$f[2] = 1;
for($i = 3;$i <= $n;$i++)
{
$f[i] = $f[$i - 1] + $f[$i - 2];
}
return $f[$n];
}
echo feibo(18);
递归算法
把问题转化为规模缩小的同类问题的子问题,然后递归调用函数(或过程)来表示问题的解;
简化问题:找最优子问题(不能再小);函数调用自己;
思想:两个重点:
递归点:发现当前问题有解决问题的函数f(n) = f(n - 1) + f(n - 2);
递归出口:当问题解决,到达最优子问题,不能再调用函数;
本质:
函数调用函数:一个函数需要开辟一块内存空间,递归会出现同时调用多个函数本身(自己):递归的本质是利用空间换时间;
ps:斐波那契数列,1 1 2 3 5 8 13 。。。得到第n位数;
规律:首位1,二位1,三位开始前两数和;
//递归要有函数
function feibo($n)
{
//递归出口
if($n == 1 || $n == 2)
return 1;
//递归点,求n的值;
return feibo($n - 1) + feibo($n - 2);
}
//调用
echo feibo(18);
冒泡排序
重复走访要排序的数列,一次比较两个元素,顺序错误就交换位置,重复到没有需要交换的元素;
思路:
比较相邻元素,第一个大于第二个就交换;对每一对相邻元素重复之前的工作;针对所有元素重复以上步骤除了最后一个;持续每次对越来越少的元素重复之前步骤,直到没有比较元素;
$arr = array(1,4,5,8,2,7,9);
//找出最大值代码,重复执行
for($i = 0,$len = count($arr);$i < $len;$i++)
{
//最大值放最右边
for($j = 0;$j < $len - 1 - $i;$j++)
{
//两两对比
if($arr[$j] > $arr[$j + 1])
{
//左 > 右:交换
$temp = $arr[$j];
$arr[$j] = $arr[$j + 1];
$arr[$j + 1] = $temp;
}
}
}
选择排序
每次从待排元素中选出最小或最大的一个元素,存放在起始位,直到待排元素全排完;(不稳定的排序)
思路:
若第一个元素最小,记住下标;寻找右侧剩余元素,若有更小的,重新记录下标;若有新的最小,交换两元素;往右重复以上步骤直到元素本身是最后一个;
$arr = array(1,4,5,9,7,3,4,2);
//确定交换次数:一次只能找到一个最小的,需要找数组长度
for($i = 0,$len = count($arr);$i < $len;$i++)
{
//假设当前第一个已排好序:为最小
$min = $i;
//拿最小的比较剩下的
for($j = $i + 1;$j < $len;$j++)
{
//比较当前元素与选定的最小元素
if($arr[$j] < $arr[$min])
{
//说明当前$min不合适
$min = $j;
}
}
//交换当前值与实际最小的值
if($min != $i)
{
$temp = $arr[$i];
$arr[$i] = $arr[$min];
$arr[$min] = $temp;
}
}
echo ‘
‘;
print_r($arr);
插入排序
将一个数据插入到已排好序的有序数据中,得到一个新的、个数加1的有序数据,算法适用少量数据的排列,较稳定。
思想:每次将一个待排序的记录按其关键码值的大小插入前面已排序文件中适当位置,直到完成。
插入排序的算法思路:
1) 设置监视哨r[0],将待插入纪录的值赋值给r[0];
2) 设置开始查找的位置j;
3) 在数组中进行搜索,搜索中将第j个纪录后移,直至r[0].key≥r[j].key为止;
4) 将r[0]插入r[j+1]的位置上。
1、 认定第一个元素已经排好序;
2、 取出第二个元素,作为待插入数据;
3、 与已经排好序的数组的最右侧元素开始进行比较
4、 如果后面的小于前面的:说明前面已经排好序的那个数组元素不在对的位置(向后移一个),然后让新的元素填充进去(继续向前比:高级)
5、 重复前面的步骤:直到当前元素插入到对位置;
6、 重复以上步骤,直到所有的数组元素都插入到对的位置。
//确定插入次数
for($i = 1,$len = count($arr);$i < $len;$i++)
{//当前插入元素值
$temp = $arr[$i];//标记:默认当前插入位置正确
$change = false;//让当前数据与前面排好序的数组元素(挨个)重复比较,直到位置交换
for($j = $i - 1;$j >= 0;$j--)
{//比较
if($arr[$j] > $temp)
{//当前元素比前面排好序的元素小,交换位置
$arr[$j + 1] = $arr[$j];//说明前面排序的数组元素有不合适的位置
$change = true;
}else{//当前元素比前面排序元素大,位置正确
break;
}
}//判断位置需要变动
if($change)
{//有数据移动,占错位了
$arr[$j + 1] = $temp;
}
}
快速排序
冒泡排序的改进方案,通过一趟排序将要排序的数据分割成独立的两部分,一部分比另一部分的数据都小,按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序排列。
快速排序的算法是:
1) 从数组中选出一个元素(通常第一个),作为参照对象。
2) 定义两个数组,将目标数组中剩余的元素与参照元素挨个比较:小的放到一个数组,大的放到另外一个数组。
3) 第二步执行完之后,前后的数组顺序不确定,但是确定了自己的位置。
4) 将得到的小数组按照第1到第3部重复操作(子问题)。
5) 回溯最小数组(一个元素)。
1 function quick_sort($arr)2 {3 //递归出口
4 $len = count($arr);5 if($len <= 1) return $arr;6 //取出一个元素,剩下的分散到两个数组中
7 $left = $right = array();8 for($i = 1;$i < $len;$i++)9 {10 //第一个元素做比较元素11 //小的放left,大的放right
12 if($arr[$i] < $arr[0])13 {14 $left[] = $arr[$i];15 }else
16 {17 $right[] = $arr[$i];18 }19 }20 //递归点:left和right没有完成排序
21 $left = quick_sort($left);22 $right = quick_sort($right);23 //合并三个数组
24 return array_merge($left,(array)$arr[0],$right);25 }
归并排序
先使每个子序列有序,再使子序列段之间有序,将已有序的子序列合并。
归并排序的算法是:
1) 将数组拆分成两个数组。
2) 重复步骤1将数组拆分成最小单元。
3) 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列.
4) 设定两个指针,最初位置分别为两个已经排序序列的起始位置。
5) 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置。
6) 重复步骤3直到某一指针超出序列尾。
7) 将另一序列剩下的所有元素直接复制到合并序列尾。
1 function merge_sort($arr)2 {3 //递归出口
4 $len = count($arr);5 if($len <= 1) return $arr;6 //拆分
7 $middle = floor($len / 2);8 //递归点:left和right没排好序,且可能是多个元素的数组
9 $left = array_slice($arr,0,$middle);10 $right = array_slice($arr,$middle);11 $left = merge_sort($left);12 $right = merge_sort($right);13 //二路归并:假设左右已排好序
14 $m = array();15 while(count($left) && count($right))16 {17 //只要$left和$right还有元素,就继续循环18 //取每个数组第一个元素比较
19 $m[] = $left[0] < $right[0] ? array_shift($left) : array_shift($right);20 }21
22 return array_merge($m,$left,$right);23 }
顺序查找
也称为线形查找,从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功;若扫描结束仍没有找到关键字等于k的结点,表示查找失败。
1 $arr = array(1,2,3,4,5,6,7,8,9);2 function check_order($arr,$num)3 {4 for($i = 0,$len = count($arr);$i < $len;$i++)5 {6 if($arr[$i] == $num)7 {8 return $i;9 }10 }11 return false;12 }
二分查找
按关键字值升序或降序排列,用给定值k先与中间结点的关键字比较,中间结点把线形表分成两个子表,若相等则查找成功;若不相等,再根据k与该中间结点关键字的比较结果确定下一步查找哪个子表,这样递归进行,直到查找到或查找结束发现表中没有这样的结点。
折半算法思路:
1、 计算数组长度;
2、 确定左右两边的指针位置;
3、 找到中间位置;
4、 匹配
5、 然后根据大小重定边界
1 function check_order($arr,$res)2 {3 //函数边界
4 $left = 0;5 $right = count($arr);6
7 while($left <= $right)8 {9 //中间位置
10 $middle = floor(($left + $right) / 2);11 //匹配数据
12 if($arr[$middle] == $res)13 {14 return $middle + 1;15 }16 //没有找到
17 if($arr[$middle] < $res)18 {19 //值在右边
20 $left = $middle + 1;21 }else
22 {23 //值在左边
24 $right = $middle - 1;25 }26 }27 return false;28 }