当前位置: 首页 > news >正文

18.PHP基础-递归递推算法

编程思想

编程思想:如何利用数学模式,来解决对应的需求问题,然后利用代码实现对应的数据模型(逻辑)

算法:使用代码实现对应的数学模型,从而解决对应的业务问题

一.递推算法

递推算法是一种简单的算法:通过已知条件,利用特定关系得出中间理论,直到得到结果的算法,递推算法分为顺推和逆推两种

顺推:

通过最简单的条件(已知),然后逐步推演结果

逆推:

通过结果找到规律,然后推到已知条件

斐波那契数列: 1 1 2 3 5 8 13…,通常需求:请求得到指定位置N所对应的值是多少

找规律:

第一个数是1 if n==1 则 n=1;

第二个数 是 1 0+1=1 if n == 2 则n=1;

第三个数是2 1+1 =2 从第三个数开始 结果= 前两个数之和 = (n-2)+(n-1)

第三个数是3 2+1=3

第N个数是前两个数之和


$num = 15;
$f[1] = 1; //已知条件
$f[2] = 1; //已知条件
for ($i = 3; $i <= $num; $i++) {$f[$i] = $f[$i - 1] + $f[$i - 2];echo $i . '=' . $f[$i] . PHP_EOL;
}
echo $f[$num];//封装
function  test2($des)
{if ($des == 1 || $des == 2) {return 1;}$f[1] = 1; //已知条件$f[2] = 1; //已知条件for ($i = 3; $i <= $des; $i++) {$f[$i] = $f[$i - 1] + $f[$i - 2];}return $f[$des];
}
echo test2(15);

二.递归算法

递归算法是把问题转换为规模缩小为的同类问题的子问题。

然后递归调用函数(或过程)来表示问题的解

1.简化问题:找到最优子问题(不能再小)

2.函数自己调用自己

斐波那契数列 :1 1 23 5 8 14

需求:求指定位置的数列的值

规律:第一个和第二个为1.从第三个开始为缉拿连个之和

F(N)=F(N-1)+F(N-2)

F(N-1)=F(N-2)+F(N-3)

F(2)=F(1)=1;

递归思想中:有两个非常重要的点

递归点:发现当前问题可以有解决当前问题的函数,去解决规模比当前小一点的问题来解决

F(N) =F(N-1)+F(N-2);

递归出口:当前问题解决的时候。已经到达(必须有)最优子问题,不能再次调用函数

如果一个函数递归调用自己而没有递归出口:就是死循环

递归的本质是函数调用函数:一个函数需要开辟一块内存空间,递归会出现同时调用N多个函数(自己):

递归的本质就是利用空间换时间

function test($n)
{if ($n <= 2) {return 1;}return test($n - 2) + test($n - 1);
};
echo test(15) . PHP_EOL;

三.数组排序

3.1 冒泡排序

冒泡排序(bubble sort)是一种计算机科学领域的较简单的排序算法

它重复地走过要排序的数列,依此比较两个元素,如果他们的书序错误就把他们交换过来。

走访数列的工作是重复地进行知道没有在需要交换,也就是说改数列已经排序完成

冒泡排序的算法思路:

1 比较相邻的元素,如果第一个比第二个大,就交换他们两个。

2、对每一对相邻元素做同样的工作,从开始第一对到结尾最后一对,在这一点,最后的元素应该是最大的书

3、针对所有的元素重复以上的步骤,除了最后一个

4、持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较

<?php
echo "<pre>";$arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
shuffle($arr);
echo "排序前:" . PHP_EOL;
print_r($arr);
//冒泡排序
//最后一个数不用排序外循环n次 内循环次数为  3+2+1
//则内循环为(n-1)+(n-2)+(n-3)+...1 = (n-1)*n/2
$n = 0;for ($i = 0, $len = count($arr) - 1; $i < $len; $i++) {//减少内循环次数for ($j = 0, $len = count($arr) - 1; $j < $len - $i; $j++) {if ($arr[$j] > $arr[$j + 1]) {$temp = $arr[$j];$arr[$j] = $arr[$j + 1];$arr[$j + 1] = $temp;}$n++;echo  $n . "内循环" . PHP_EOL;print_r($arr);}echo $i . "外循环" . PHP_EOL;print_r($arr);
}/* 
等差数列之和
(n - 1) + (n - 2) + ... + 1 
1 + 2 + 3 + ... + (n-1)//倒着写
头尾相加 (n-1)+1 +(n-2)+2+(n-3)+3+... =
那一共多少对呢? 
1+2+3
3+2+1 n*(n - 1)/2 用 “(首项 + 末项) × 项数÷ 2” //项数(n-1) 
//头+尾巴 (n-1)+1 =n
//结果就是(n-1)*n/2所以如果n = 3那么内循环次数是 (3-1) 3/2 = 3*2/2=3
如果n=10 就是9*10/2=45*/
echo "</pre>";

简单示意图:例如[3,2,1]

请添加图片描述

3.2 选择排序

选择排序(selection sort)

是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。选择排序是最不稳定的排序方式(比如[5,5,3]第一次就讲第一个[5]与[3]交换,导致第一个5移动到了第二个5后面

选择排序的算法思路:

1、假设第一个元素是最小元素,记下下标

2、寻找右侧剩余的元素,如果有更小的,重新记下最新的下标

3、一轮结束后,锁定最小的标志位,交换当前外循环位置的下标与最小标志位下标的元素

4、往右重复以上步骤,直到元素本身是最后一个

$arr = [1, 2, 3, 4, 5, 6];
shuffle($arr);
echo "排序前" . PHP_EOL;
print_r($arr);
$num = 0;//选择排序 交换次数减少 性能比冒泡排序性能高
for ($i = 0; $i < count($arr) - 1; $i++) {$minIndex = $i;for ($j = $i + 1; $j < count($arr); $j++) {if ($arr[$j] < $arr[$minIndex]) {$minIndex = $j;}$num++;echo "第{$num}轮";}if ($minIndex != $i) {$temp = $arr[$i];$arr[$i] = $arr[$minIndex];$arr[$minIndex] = $temp;}
}

3.3 插入排序

插入排序(Insert sort)

插入排序的基本操作是将一个数据插入到已经排好序的有序数据中,从而得到一个新的,个数加1的有序数据,算法适用于少量数据的排序,是稳定的排序方法。

插入算法把要排序的数组分成两部分:

第一部分:左边是已经排好序的部分(从第 0 个元素开始,一开始它只有 1 个元素,所以天然有序)

第二部分:右边是还没插进去的部分(从第 1 个元素开始,每个轮到它的时候,就准备把它插到左边去)

插入排序的算法思路:

  1. 从数组第二个元素开始处理(因为第一个元素天然有序)
  2. 每次拿出这个元素(key)
  3. 从前一位开始向左扫描
  4. 只要发现比 key 大的,就把它们统统往右挪
  5. 直到找到不比 key 大的位置
  6. 在这个位置把 key 插进去
function test($arr)
{$len = count($arr);for ($i = 1; $i < $len; $i++) {$key = $arr[$i]; //当前要插入的值$j = $i - 1;while ($j >= 0 && $arr[$j] > $key) {$arr[$j + 1] = $arr[$j]; //向后挪动一位$j--; //再判断前列的元素}$arr[$j + 1] = $key; //如果进入的循环插入到列的空出来的位置//如果没有进入循环,则插入到末尾 }return $arr;
}
// 测试
$nums = [5, 2, 8, 3, 1];
$result = test($nums);
print_r($result);

也可以倒过来

第一部分是无序区从第一个元素到倒数第二个

第二部分是有序区 最后一个元素

function reverseInsertSort($arr)
{$len = count($arr);// 最后一个元素作为初始有序区for ($i = $len - 2; $i >= 0; $i--) { // 从倒数第二个开始$key = $arr[$i];$j = $i + 1;// 向后移动有序区元素while ($j < $len && $arr[$j] < $key) {$arr[$j - 1] = $arr[$j];$j++;}$arr[$j - 1] = $key;}return $arr;
}// 测试
$nums = [5, 2, 8, 3, 1];
print_r(reverseInsertSort($nums));

有个网站可以帮助动画理解:

https://visualgo.net/zh/sorting

如下:
请添加图片描述

请添加图片描述

3.4 快速排序

快速排序(quick sort) 是对冒泡排序的一种改进。

通过一趟排序将要排序的数据分科成独立的两部分。

其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按照此方法对着两部分数据分别进行快速排序,整个排序过程可以递归进行,一次达到整个数据变成有序序列

设 要排序的数组是A[0]…A[N-1] ,首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比他小的数都放到它前面,所有比它大的数据都放到它后面,这个过程称为一趟快速排序。

值得注意的是,快速排序不是一种稳定点的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动

快速排序的算法是:

1、从数组中选出一个元素(通常是第一个),作为惨超对象。

2、定义两个数组,将目标数组中剩余的元素与参照元素挨个比较:

小的放到一个数组,大的放到另外一个数组

3、第二步执行完以后,前后的数组顺序不确定,但确定了自己的位置

4、将得到的小数组按照第1到第3部重复操作(子问题)

5、回溯最小数组(一个元素)。

实现代码

<?php
echo "<pre>";
function test($arr)
{$len = count($arr);//如果数组元素为1 结束快排if ($len <= 1) return $arr; //返回数组本身 可能有一边是空数组//快速排序$leftArr =  $rightArr = [];for ($i = 1; $i < $len; $i++) {$value = $arr[$i]; //比较的值$middleValue = $arr[0]; //基准if ($middleValue > $value) {array_push($leftArr, $value);// $leftArr[] = $value//小于等于的情况划分到另一个组} else {array_push($rightArr, $value);// $rightArr[] = $value}}$res =  [...test($leftArr), $arr[0], ...test($rightArr)];//array_merge(test($leftArr),(array)$arr[0],test($rightArr));print_r($res);return $res;
}
$arr = [1, 2, 3, 3, 4, 5];
shuffle($arr);
print_r($arr);
$res = test($arr);
print_r($res);
echo "</pre>";

3.5 归并排序

conquer-征服,治服,战胜,胜利

归并排序(merge-sort)是建立在归并操作上的一种有效的排序算法,该算法采用分治法(divide and conquer)

的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列,即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并

归并排序的算法是:

1、将数组拆分成两个数组

2、重复步骤1将数组拆分成最小单元

3、申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

4、设定两个指针,最初位置分别为两个已经排序序列的起始位置

5、比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位

6、重复步骤三知道某指针拆除序列尾

7、将另一序列剩下的所有元素直接复制到合并序列尾

可参考https://cs50.harvard.edu/x/2022/notes/3/#merge-sort

代码实现:

function merge_sort($arr)
{$len = count($arr);//递归出口if ($len <= 1) return $arr;//拆分 $middle = floor($len / 2);$left = array_slice($arr, 0, $middle);$right = array_slice($arr, $middle);//递归点:$left和$right都没有排好序:而且可能是多个元素的数组$left = merge_sort($left);$right = merge_sort($right);//假设左边和右边都已经排好序:二路归并$m = array();while (count($left) && count($right)) {//只要$arr1和$arr2里面还有元素,就进行循环//取出每个数组的第一个元素:进行比较$m[] = $left[0] < $right[0] ? array_shift($left) : array_shift($right);}//返回结果 return array_merge($m, $left, $right);
};

四.查找算法

4.1 概念

查找是在大量的信息中寻找一个特定的信息元素,在计算机应用中,查找是常用的基本运算,查找算法是指实现查找过程对应的代码结

4.2 顺序查找算法

顺序查找算法也称为线性查找,从数据结构线性表的一段开始,顺序扫描,依此将扫描到的结点关键字与给定值k相比较,如果相等则表示查找成功,若扫描结束仍没有找到关键字等于k的结点,表示查找失败

代码实现:

$arr = array(1, 3, 4);
//顺序查找
function  test($arr, $num)
{foreach ($arr as $key => $value) {if ($value == $num) {return $key;}}return false;
}
var_dump(test($arr, 3));

4.3 二分查找算法

二分查找要求线性表中的结点按照关键字升序或降序排列,用给定值k与中间结点的关键字相比较,总监结点吧线性表分成两个子表,若相等则查找成功,若不相等,再根据k与该中间结点关键字的比较结果确定下一步查找哪个子表,这样递归进行,直到查询到查找结束发现表中没有这样的结点。

代码实现

//二分查找算法
//1.得到数组边界
$arr = [1, 3, 6, 8, 23, 68, 100];
$res  = 68;
function test2($arr, $res)
{$right = count($arr) - 1;$left = 0;//2.循环匹配while ($left <= $right) {//3.得到中间位置$middle = floor(($right + $left) / 2);//4.匹配数据if ($arr[$middle] == $res) {return $middle;}//5.没有找到if ($arr[$middle] < $res) {//值在右边$left = $middle + 1;} else {//值在左边$right = $middle - 1;}}return false;
}
var_dump(test2($arr, $res));
http://www.dtcms.com/a/613688.html

相关文章:

  • 郑州软件开发公司网站广西医院的网站建设
  • 费县做网站职业教育专业建设验收网站
  • 第五章 防火墙设备互联
  • 建导航网站seo企业优化顾问
  • 2025.11.15 力扣每日一题
  • LeetCode算法日记 - Day 104: 通配符匹配
  • RDMA内存保护概念---MR,PD
  • 11月13号作业
  • 怎样建立网站目录结构炒股网站开发
  • 【STM32MP157 异核通信框架学习篇】(10)Linux下Remoteproc相关API (上)
  • 东莞企业建站平台中企动力 做网站 怎么样
  • 虚拟机的未来:从云计算到量子模拟
  • 前端响应式设计资源,框架+模板
  • 品牌网站建设服务网络品牌塑造
  • C语言编译系统 | 高效编译与优化技术分析
  • L2层差错控制与HARQ协议介绍
  • 4. Qt深入 线程和QObject
  • 印尼游戏出海合规指南:法律框架、税务政策与运营挑战
  • 【Java Web学习 | 第11篇】JavaScript(5)BOM
  • 打造您专属的高效DNS解析器:RethinkDNS
  • 网上书店网站建设方案策划如何建设好一个网站
  • Spring Framework 中文官方文档
  • 深度剖析 C++ vector的底层实现
  • USDe:站在稳定币、永续化与资产代币化三大趋势交汇点的新型美元
  • SpringBoot 2.x 升级到 3.x 时 Swagger 迁移完整指南
  • 网站首页浮动窗口代码忘记了wordpress登录密码忘记
  • springMVC(3)学习
  • 负载均衡API测试
  • 门户类网站费用淘宝网站边上的导航栏怎么做
  • oralce创建种子表,使用存储过程生成最大值sql,考虑并发,不考虑并发的脚本,plsql调试存储过程,java调用存储过程示例代码