数据结构之利用PHP实现二分搜索树


Posted in PHP onOctober 25, 2020

前言

这篇文章是介绍 二叉树 和 二分搜索树,然后通过 PHP 代码定义一下 二分搜索树 的节点,使用递归思想操作向二分搜索树添加元素,然后实现了递归判断二分搜索树上是否包含某个元素,最后分别实现了前序遍历、中序遍历、后序遍历 二分搜索树。

1.二叉树

1.1 二叉树图示

数据结构之利用PHP实现二分搜索树

1.2 二叉树节点定义

//二叉树具有唯一根节点
class Node{
 $e; //节点元素
 $left; //左儿子
 $right;//右儿子
}

Tips:二叉树每个节点最多有两个儿子,每个节点最多有一个父亲。

1.3 二叉树的特点

  • 二叉树具有天然的递归结构,每个节点的左儿子或右儿子也是 二叉树。
  • 二叉树不一定是满的,可能只有左儿子或又儿子。
  • 一个节点或 NULL 也可以看做一个二叉树。

2.二分搜索树

2.1 二分搜索树特点

  • 二分搜索树是二叉树。
  • 每个节点的元素的值都要大于左儿子所有节点的值。
  • 每个节点的元素的值都要小于右儿子所有节点的值。
  • 每个子树也是二分搜索树。
  • 二分搜索树查询速度快。
  • 存储的元素必须要有比较性。

2.2 二分搜索树图示

数据结构之利用PHP实现二分搜索树

2.3 PHP 代码定义节点

class Node
{
 public $e;
 public $left = null;
 public $right = null;
 /**
  * 构造函数 初始化节点数据
  * Node constructor.
  * @param $e
  */
 public function __construct($e) {
  $this->e = $e;
 }
}

2.4 向二分搜索树添加元素

下面展示的的使用递归思想向二分搜索树添加元素,其中 add($e) 方法表示想二分搜索树添加元素 $e,recursionAdd(Node $root, $e) 是一个递归函数,表示使用递归向二分搜索树添加元素:

/**
  * 向二分搜索树添加元素
  * @param $e
  */
 public function add($e) {
  $this->root = $this->recursionAdd($this->root, $e);
 }
 /**
  * 递归向二分搜索树添加元素
  * @param Node $root
  * @param $e
  */
 public function recursionAdd(Node $root, $e) {
  if ($root == null) { //若节点为空则添加元素 并且返回当前节点信息
   $this->size++;
   $root = new Node($e);
  } elseif ($e < $root->e) { //若元素小于当前节点元素 则向左节点递归添加元素
   $root->left = $this->recursionAdd($root->left, $e);
  } elseif ($e > $root->e) { //若元素大于当前节点元素 则向右节点递归添加元素
   $root->right = $this->recursionAdd($root->right, $e);
  } //若元素等于当前节点元素 则什么都不做
 }

Tips:这里的二分搜索树不包含重复元素,如果想要包含重复元素,可以定义每个左儿子所有元素小于等于父亲节点,或者每个节点右儿子所有节点元素大于等于父亲节点。

2.5 查询二分搜索树是否包含某个元素

下面展示的的使用递归思想查询二分搜索树元素是否包含某个元素,其中 contains($e) 方法表示查询二分搜索树是否包含元素 $e,recursionContains(Node $root, $e) 是一个递归函数,表示使用递归查询二分搜索树元素:

/**
  * 判断二分搜索树是否包含某个元素
  * @param $e
  * @return bool
  */
 public function contains($e): bool {
  return $this->recursionContains($this->root, $e);
 }
 /**
  * 递归判断二分搜索树是否包含某元素
  * @param $root
  * @param $e
  * @return bool
  */
 private function recursionContains(Node $root, $e): bool {
  if ($root == null) { //若当前节点为空 则表示不存在元素 $e
   return false;
  } elseif ($e == $root->e) { //若 $e 等于当前节点元素,则表示树包含元素 $e
   return true;
  } elseif ($e < $root->e) { //若 $e 小于当前节点元素,则去左儿子树递归查询是否包含节点
   return $this->recursionContains($root->left, $e);
  } else { //若 $e 大于当前节点元素,则去右儿子树递归查询是否包含节点
   return $this->recursionContains($root->right, $e);
  }
 }

Tips:递归的时候会比较元素和节点的值,递归的时候判断元素大小相当于 “指路”,最终指向到的位置就是判断是否包含元素是否存在的依据。

2.6 二分搜索树前序遍历

前序遍历操作就是把所有节点都访问一次,前序遍历 是先访问节点,再递归遍历左儿子树,然后再递归遍历右儿子树:

/**
  * 前序遍历
  */
 public function preTraversal() {
  $this->recursionPreTraversal($this->root, 0);
 }
 /**
  * 前序遍历的递归
  */
 public function recursionPreTraversal($root, $sign_num) {
  echo $this->getSign($sign_num);//打印深度
  if ($root == null) {
   echo "null<br>";
   return;
  }
  echo $root->e . "<br>"; //打印当前节点元素
  $this->recursionPreTraversal($root->left, $sign_num + 1);
  $this->recursionPreTraversal($root->right, $sign_num + 1);
 }

下面是打印结果:

<?php
require 'BinarySearchTree.php';
$binarySearchTree = new BinarySearchTree();
$binarySearchTree->add(45);
$binarySearchTree->add(30);
$binarySearchTree->add(55);
$binarySearchTree->add(25);
$binarySearchTree->add(35);
$binarySearchTree->add(50);
$binarySearchTree->add(65);
$binarySearchTree->add(15);
$binarySearchTree->add(27);
$binarySearchTree->add(31);
$binarySearchTree->add(48);
$binarySearchTree->add(60);
$binarySearchTree->add(68);
//下面是预期想要的结果
/**
 *                     45
 *           /                  
 *          30                   55
 *        /                    /   
 *      25       35         50       65
 *     /       /          /       /  
 *   15   27  31         48       60     68
 *
 */
$binarySearchTree->preTraversal();
/**
打印输出
45
-----30
----------25
---------------15
--------------------null
--------------------null
---------------27
--------------------null
--------------------null
----------35
---------------31
--------------------null
--------------------null
---------------null
-----55
----------50
---------------48
--------------------null
--------------------null
---------------null
----------65
---------------60
--------------------null
--------------------null
---------------68
--------------------null
--------------------null
 */

Tips:可以看到打印输出结果和预期一致。

2.7 二分搜索树中序遍历

遍历操作就是把所有节点都访问一次,后序遍历 是先递归遍历右儿子树,再访问节点,然后再递归遍历右儿子树,最后的顺序输出结果是有序的:

/**
  * 中序遍历
  */
 public function midTraversal() {
  $this->recursionMidTraversal($this->root, 0);
 }
 /**
  * 中序遍历的递归
  */
 public function recursionMidTraversal($root, $sign_num) {
  if ($root == null) {
   echo $this->getSign($sign_num);//打印深度
   echo "null<br>";
   return;
  }
  $this->recursionMidTraversal($root->left, $sign_num + 1);
  echo $this->getSign($sign_num);//打印深度
  echo $root->e . "<br>";
  $this->recursionMidTraversal($root->right, $sign_num + 1);
 }

下面是打印结果:

<?php
require 'BinarySearchTree.php';
$binarySearchTree = new BinarySearchTree();
$binarySearchTree->add(45);
$binarySearchTree->add(30);
$binarySearchTree->add(55);
$binarySearchTree->add(25);
$binarySearchTree->add(35);
$binarySearchTree->add(50);
$binarySearchTree->add(65);
$binarySearchTree->add(15);
$binarySearchTree->add(27);
$binarySearchTree->add(31);
$binarySearchTree->add(48);
$binarySearchTree->add(60);
$binarySearchTree->add(68);
//下面是预期想要的结果
/**
 *                     45
 *           /                  
 *          30                   55
 *        /                    /   
 *      25       35         50       65
 *     /       /          /       /  
 *   15   27  31         48       60     68
 *
 */
$binarySearchTree->midTraversal();
/**
打印输出
--------------------null
---------------15
--------------------null
----------25
--------------------null
---------------27
--------------------null
-----30
--------------------null
---------------31
--------------------null
----------35
---------------null
45
--------------------null
---------------48
--------------------null
----------50
---------------null
-----55
--------------------null
---------------60
--------------------null
----------65
--------------------null
---------------68
--------------------null
 */

Tips:可以看到打印输出结果和预期一致,但是此时的遍历顺序变了,最后的顺序输出结果是有序的。

2.8 二分搜索树后序遍历

遍历操作就是把所有节点都访问一次,后序遍历 是先递归遍历左儿子树,然后再递归遍历右儿子树,再访问节点:

/**
  * 后序遍历
  */
 public function rearTraversal() {
  $this->recursionRearTraversal($this->root, 0);
 }
 /**
  * 后序遍历的递归
  */
 public function recursionRearTraversal($root, $sign_num) {
  if ($root == null) {
   echo $this->getSign($sign_num);//打印深度
   echo "null<br>";
   return;
  }
  $this->recursionRearTraversal($root->left, $sign_num + 1);
  $this->recursionRearTraversal($root->right, $sign_num + 1);
  echo $this->getSign($sign_num);//打印深度
  echo $root->e . "<br>";
 }

下面是打印结果:

<?php
require 'BinarySearchTree.php';
$binarySearchTree = new BinarySearchTree();
$binarySearchTree->add(45);
$binarySearchTree->add(30);
$binarySearchTree->add(55);
$binarySearchTree->add(25);
$binarySearchTree->add(35);
$binarySearchTree->add(50);
$binarySearchTree->add(65);
$binarySearchTree->add(15);
$binarySearchTree->add(27);
$binarySearchTree->add(31);
$binarySearchTree->add(48);
$binarySearchTree->add(60);
$binarySearchTree->add(68);
//下面是预期想要的结果
/**
 *                     45
 *           /                  
 *          30                   55
 *        /                    /   
 *      25       35         50       65
 *     /       /          /       /  
 *   15   27  31         48       60     68
 *
 */
$binarySearchTree->rearTraversal();
/**
打印输出
--------------------null
--------------------null
---------------15
--------------------null
--------------------null
---------------27
----------25
--------------------null
--------------------null
---------------31
---------------null
----------35
-----30
--------------------null
--------------------null
---------------48
---------------null
----------50
--------------------null
--------------------null
---------------60
--------------------null
--------------------null
---------------68
----------65
-----55
45
 */

代码仓库 :https://gitee.com/love-for-po...

总结

到此这篇关于数据结构之利用PHP实现二分搜索树的文章就介绍到这了,更多相关PHP实现二分搜索树内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

PHP 相关文章推荐
echo, print, printf 和 sprintf 区别
Dec 06 PHP
PHP简洁函数(PHP简单明了函数语法)
Jun 10 PHP
php自定义session示例分享
Apr 22 PHP
php中mysql连接和基本操作代码(快速测试使用,简单方便)
Apr 25 PHP
php实现转换ubb代码的方法
Jun 18 PHP
php注册登录系统简化版
Dec 28 PHP
php使用正则验证中文
Apr 06 PHP
关于php中的json_encode()和json_decode()函数的一些说明
Nov 20 PHP
PHP编程实现微信企业向用户付款的方法示例
Jul 26 PHP
浅析PHP开发规范
Feb 05 PHP
使用laravel的migrate创建数据表的方法
Sep 30 PHP
PhpStorm的使用教程(本地运行PHP+远程开发+快捷键)
Mar 26 PHP
如何运行/调试你的PHP代码
Oct 23 #PHP
php redis setnx分布式锁简单原理解析
Oct 23 #PHP
PHP如何通过带尾指针的链表实现'队列'
Oct 22 #PHP
php使用event扩展的io复用测试的示例
Oct 20 #PHP
Aliyun Linux 编译安装 php7.3 tengine2.3.2 mysql8.0 redis5的过程详解
Oct 20 #PHP
phpcmsv9.0任意文件上传漏洞解析
Oct 20 #PHP
php实现记事本案例
Oct 20 #PHP
You might like
Yii2 rbac权限控制之rule教程详解
2016/06/23 PHP
laravel学习教程之关联模型
2016/07/30 PHP
php表单文件iframe异步上传实例讲解
2017/07/26 PHP
神奇的7个jQuery 3D插件整理
2011/01/06 Javascript
jquery focus(fn),blur(fn)方法实例代码
2011/12/16 Javascript
让低版本浏览器支持input的placeholder属性(js方法)
2013/04/03 Javascript
javascript创建createXmlHttpRequest对象示例代码
2014/02/10 Javascript
javascript实现复选框超过限制即弹出警告框的方法
2015/02/25 Javascript
简介JavaScript中的unshift()方法的使用
2015/06/09 Javascript
JSON字符串和对象相互转换实例分析
2016/06/16 Javascript
AngularJs  E2E Testing 详解
2016/09/02 Javascript
js实现动态显示时间效果
2017/03/06 Javascript
vue.js实现单选框、复选框和下拉框示例
2017/07/18 Javascript
Node.js readline模块与util模块的使用
2018/03/01 Javascript
重新认识vue之事件阻止冒泡的实现
2018/08/02 Javascript
atom-design(Vue.js移动端组件库)手势组件使用教程
2019/05/16 Javascript
antd的select下拉框因为数据量太大造成卡顿的解决方式
2020/10/31 Javascript
ES6学习教程之Promise用法详解
2020/11/22 Javascript
[02:18]DOTA2英雄基础教程 育母蜘蛛
2014/01/20 DOTA
Python中使用Queue和Condition进行线程同步的方法
2016/01/19 Python
Python抓取电影天堂电影信息的代码
2016/04/07 Python
Python如何筛选序列中的元素的方法实现
2019/07/15 Python
python自动化UI工具发送QQ消息的实例
2019/08/27 Python
python socket 聊天室实例代码详解
2019/11/14 Python
python 计算方位角实例(根据两点的坐标计算)
2020/01/17 Python
OpenCV 之按位运算举例解析
2020/06/19 Python
实现Python3数组旋转的3种算法实例
2020/09/16 Python
Python中读取文件名中的数字的实例详解
2020/12/25 Python
canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动
2018/01/10 HTML / CSS
墨尔本最受欢迎的复古风格品牌:Princess Highway
2018/12/21 全球购物
工业设计专业推荐信
2013/10/29 职场文书
大学四年个人的自我评价
2014/02/26 职场文书
2014年乡镇民政工作总结
2014/12/02 职场文书
南极大冒险观后感
2015/06/05 职场文书
户外拓展训练感想
2015/08/07 职场文书
承诺书的签字人,需不需要承担相应的责任?
2019/07/09 职场文书