利用PHP实现递归删除链表元素的方法示例
作者:爱因诗贤 发布时间:2024-04-23 09:09:41
前言
这篇文章介绍一下 递归,递归的本质是将原来的问题转化为更小的同一个问题,解决这些更小问题的过程。下面通过两个递归的例子帮助学习对递归的理解。
1.递归数组求和
例如某个数组 $arr = [1,2,3,4,5,6,7,8,9,10]; 需要求和,通过实现递归函数对数组求和来帮助学习对递归的理解。
1.1 输出文件 output_recursion.php
<?php
require 'ArrayRecursion.php';
/**
* 递归实现数组求和
*/
$arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
echo ArrayRecursion::recursionSum($arr);
1.2 ArrayRecursion 类
这是一个实现数组递归求和的代码,其中 recursionSum() 是一个递归函数,相当于把求和过程转化为更小的求和,最终实现想要的结果:
<?php
/**
* 使用递归对数组求和 方便对递归的理解
* Class ArrayRecursion
*/
class ArrayRecursion
{
public static function sum(array $arr) {
return self::recursionSum($arr);
}
public static function recursionSum(array $arr, $i = 0) {
if (count($arr) == $i) {
return 0;
}
return $arr[$i] + self::recursionSum($arr, $i + 1);
}
}
Tips:这个求和过程仅仅只是帮助学习递归思想,实际求和可以直接遍历数组。
2.递归删除链表某个元素
例如某个链表 10->9->8->99->7->99->6->5->99->4->3->2->1->null 需要删除其中值等于 99 的元素,可以通过实现递归来得到删除指定元素的效果。
2.1 输出文件 output_recursion.php
<?php
require 'LinkedList.php';
require 'LinkedListRecursion.php';
/**
* 首先实例化一个链表,向链表中添加50个元素
*/
$linkedList = new LinkedList();
for ($i = 0; $i < 50; $i++) {
if ($i % 7 == 0) {
$linkedList->addFirst(99);
} else {
$linkedList->addFirst($i);
}
}
echo $linkedList->toString();
/**打印链表中元素
* 99->48->47->46->45->44->43->99->41->40->39->
* 38->37->36->99->34->33->32->31->30->29->99->27->
* 26->25->24->23->22->99->20->19->18->17->16->15->
* 99->13->12->11->10->9->8->99->6->5->4->3->2->1->99->null
*/
//将链表对象传入一个能删除指定元素的方法,如 99
echo LinkedListRecursion::deleteElement($linkedList, 99)->toString();
/**打印
* 48->47->46->45->44->43->41->40->
* 39->38->37->36->34->33->32->31->
* 30->29->27->26->25->24->23->22->
* 20->19->18->17->16->15->13->12->
* 11->10->9->8->6->5->4->3->2->1->null
*/
2.2 LinkedList & Node 链表类
这是一个链表类,可以使用 addFirst() 方法向链表头部添加元素,可使用 getHead() 获取链表 head 节点对象信息,可以使用 setHead() 改变 head,另外下面定义了一个链表节点类 Node:
<?php
/**
* 链表的实现
* Class LinkedList
*/
class LinkedList
{
private $dummyHead;
private $size;
/**
* 初始化链表 null->null
* LinkedList constructor.
*/
public function __construct() {
$this->dummyHead = new Node(null, null);
$this->size = 0;
}
/**
* 获取链表大小
* @return int
*/
public function getSize(): int {
return $this->size;
}
/**
* 判断链表是否为空
* @return bool
*/
public function isEmpty(): bool {
return $this->size == 0;
}
/**
* 在链表的第 index 位置添加元素
* @param int $index
* @param $e
*/
public function add(int $index, $e): void {
if ($index < 0 || $index > $this->size) {
echo "索引范围错误";
exit;
}
$prve = $this->dummyHead;
for ($i = 0; $i < $index; $i++) {
$prve = $prve->next;
}
//将上插入位置的上一个位置的 next 节点指向插入节点,插入节点的 next 节点信息指向原上节点的 next 节点
$prve->next = new Node($e, $prve->next);
$this->size++;
}
/**
* 向链表开头添加元素
* @param $e
*/
public function addFirst($e): void {
$this->add(0, $e);
}
/**
* 向链表末尾添加元素
* @param $e
*/
public function addLast($e): void {
$this->add($this->size, $e);
}
/**
* 获取链表第 index 位置元素
* @param $index
*/
public function get($index) {
if ($index < 0 || $index > $this->size) {
echo "索引范围错误";
exit;
}
$node = $this->dummyHead;
for ($i = 0; $i < $index + 1; $i++) {
$node = $node->next;
}
return $node->e;
}
/**
* 获取链表第一个元素
* @return mixed
*/
public function getFirst() {
return $this->get(0);
}
/**
* 获取链表最后一个元素
* @return mixed
*/
public function getLast() {
return $this->get($this->size - 1);
}
/**
* 修改链表中第 index 位置元素值
* @param $index
* @param $e
*/
public function update($index, $e) {
if ($index < 0 || $index > $this->size) {
echo "索引范围错误";
exit;
}
$node = $this->dummyHead;
for ($i = 0; $i < $index + 1; $i++) {
$node = $node->next;
}
$node->e = $e;
}
/**
* 判断链表中是否存在某个元素
* @param $e
* @return bool
*/
public function contains($e): bool {
for ($node = $this->dummyHead->next; $node != null; $node = $node->next) {
if ($node->e == $e) {
return true;
}
}
return true;
}
/**
* 删除链表中第 index 位置元素
* @param $index
*/
public function remove($index) {
if ($index < 0 || $index > $this->size) {
echo "索引范围错误";
exit;
}
if ($this->size == 0) {
echo "链表已经是空";
exit;
}
$prve = $this->dummyHead;
for ($i = 0; $i < $index; $i++) {
$prve = $prve->next;
}
$node = $prve->next;
$prve->next = $node->next;
$this->size--;
return $node->e;
}
/**
* 删除链表头元素
*/
public function removeFirst() {
return $this->remove(0);
}
/**
* 删除链表末尾元素
*/
public function removeLast() {
return $this->remove($this->size - 1);
}
/**
* 获取头结点信息
* @return mixed
*/
public function getHead() {
return $this->dummyHead->next;
}
/**
* 设置头
* @param Node $head
*/
public function setHead(Node $head) {
$this->dummyHead->next = $head;
}
/**
* 链表元素转化为字符串显示
* @return string
*/
public function toString(): string {
$str = "";
for ($node = $this->dummyHead->next; $node != null; $node = $node->next) {
$str .= $node->e . "->";
}
return $str . "null";
}
}
class Node
{
public $e;//节点元素
public $next; //下个节点信息
/**
* 构造函数 设置节点信息
* Node constructor.
* @param $e
* @param $next
*/
public function __construct($e, $next) {
$this->e = $e;
$this->next = $next;
}
}
2.3 LinkedListRecursion 类
这个类定义了一个 deleteElement(LinkedList $linkedList, $val) 方法可以将传进的链表类中指定元素值的节点删除掉(实际是节点的 next 重新指向),recursionDelete($head, $val) 方法是一个递归函数,它能递归删除 head 中指定元素值等于 $val 的节点删除:
<?php
/**
* 递归删除链表指定元素
* Class LinkedListRecursion
*/
class LinkedListRecursion
{
public static function deleteElement(LinkedList $linkedList, $val) {
$linkedList->setHead(self::recursionDelete($linkedList->getHead(), $val));
return $linkedList;
}
/**
* 递归函数 递归删除链表元素
* @param $head
* @param $val
* @return null
*/
private static function recursionDelete($head, $val) {
if ($head == null) {
return null;
} else {
if ($head->e == $val) {
return self::recursionDelete($head->next, $val);
} else {
$head->next = self::recursionDelete($head->next, $val);
return $head;
}
}
}
}
代码仓库 :https://gitee.com/love-for-po...
来源:https://segmentfault.com/a/1190000037572830


猜你喜欢
- Go文档中展示了多种方式实现外部资源嵌入,包括文本文件、图片、ios文件等:文本文件package mainimport _ "e
- 随机数和蒙特卡洛模拟求解单一变量非线性方程求解线性系统方程函数的数学积分常微分方程的数值解等势线绘图和曲线:等势线 import
- 随着移动端的用户越来越多,传统的web系统架构无法兼容很多移动终端的正常使用。在工作中也会发现,现在很多的客户都有在手机、平板等移动终端上使
- 1 输出大写字母、小写字母、大小写字母、数字、大小写字母和数字1.1输出小写:找到小写a(97)到z(122)的的ASCII码,然后转义为字
- 前言在我们开发的过程中,我们会使用webpack-dev-server实现自动刷新,webpack-dev-server会把编译后的文件全部
- 本文研究的主要是python中协程的相关问题,具体介绍如下。Num01–>协程的定义协程,又称微线程,纤程。英文名Coroutine。
- python3.6.4安装opencv3.4.2使用pip安装OpenCV直接安装最新版:pip3 install opencv_pytho
- 主要介绍常用的MySQL命令,包括连接数据库,修改密码,管理用户,操作数据库,操作数据表,数据库备份等,每个命令都配有实例说明,让大家更容易
- 我想要的结果无非是去掉URL路径中的index.php首先是配置.htaccess<IfModule mod_rewrite.c>
- Fabric是一个用Python开发的部署工具,最大特点是不用登录远程服务器,在本地运行远程命令,几行Python脚本就可以轻松部署。文档入
- 引言最近公司换了电脑,系统也从 win7 升级到 win11,开发环境都重新安装了一遍,然后在 idea 用mvn 执行打包命令 mvn c
- 内容摘要: Request和Response这两个对象是ASP所提供的内置对象中最常用的两个。在浏览器(或其他用户代理)和Web服
- 目录一、进程(Process)二、线程(Thread)三、并发编程解决方案:四、多线程实现 (两种)1、第一种 函数方法2、第二种 类方法包
- 前言本笔记通过记录 数据包 在网络中的生命履历来引出一些网络基础知识,如:MAC、ARP、IP、子网掩码、网关、集线器、交换机、路由器这些概
- 如果您刚刚开始接触网页设计,是不是经常发生这样的问题呢?做好的网页在自己机器上可以正常浏览,而把页面传到服务器上就总是出现看不到图片,css
- 前言今天跟大家介绍一个开源项目:id-maker,主要功能是用来在分布式环境下生成唯一 ID。上周停更了一周,也是用来开发和测试这个项目的相
- 今天看了篇关于Web Form Design的成功案例,虽然讲的事情很简单,但总结了一些方法,翻译过来做个原始积累吧,以后写东西举例子时也好
- 一、python批量解压提示:如果是重要数据解压前请先备份,解压后会覆盖原压缩文件!!解压前:解压后:文件名为英文:文件名中包含中文:代码如
- 训练完目标检测模型之后,需要评价其性能,在不同的阈值下的准确度是多少,有没有漏检,在这里基于IoU(Intersection over Un
- 实现思路和详细解读1. 获取 Fashion 数据、处理数据(1)本次实践项目用到的是 Fashion 数据集,包含 10 个类别的服饰灰度