二叉排序树详解——PHP代码实现
二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。
一、定义
二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
- 若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
- 左、右子树也分别为二叉排序树;
如果按照中序遍历一个二叉排序树得到的是一个从小到大排好序的数据集。构造一棵二叉排序树的目的,并不是为了排序,而是为了提高查找和插入删除关键字的速度。不管怎么说,在一个有序数据集上的查找,速度总是要快于无序的数据集的,而二叉排序树这种非线性的结构,也有利于插入和删除的实现。
二、二叉排序树的查找
首先构建节点类,如下
<?php
/**
* Node.php
* Created on 2019/4/27 9:09
* Created by Wilin
*/ class Node {
public $data;
public $left = null;
public $right = null; public function __construct($data) {
$this->data = $data;
}
}
中序遍历方法如下
<?php
/**
* Traverse.php
* Created on 2019/4/27 11:10
* Created by Wilin
*/
function midOrderTraverse($tree) {
if($tree == null) {
return;
} midOrderTraverse($tree->left);
printf("%s\n", $tree->data);
midOrderTraverse($tree->right);
}
二叉排序树类基本结构如下:
<?php
/**
* BinarySortedTree.php
* Created on 2019/4/27 11:03
* Created by Wilin
*/ include "Node.php";
include "../Traverse.php"; class BinarySortedTree
{
private $tree; public function getTree() {
return $this->tree;
}
}
下面开始往二叉排序树中添加查找方法。
查找步骤:
- 若根结点的关键字值等于查找的关键字,成功。
- 否则,若小于根结点的关键字值,递归查左子树。
- 若大于根结点的关键字值,递归查右子树。
- 若子树为空,查找不成功。
根据该步骤,编写出如下查找代码
public function find(int $data) {
$p = $this->tree;
while ($p) {
if ($data < $p->data) {
$p = $p->left;
} elseif ($data > $p->data) {
$p = $p->right;
} else {
return $p;
}
}
return null;
}
三、二叉排序树的插入
插入步骤
- 首先执行查找算法,找出被插结点的父亲结点。
- 判断被插结点是其父亲结点的左、右儿子。将被插结点作为叶子结点插入。
- 若二叉树为空。则首先单独生成根结点。
注意:新插入的结点总是叶子结点。
根据插入步骤,编写出如下插入代码
public function insert(int $data) {
if (!$this->tree) {
$this->tree = new Node($data);
return true;
}
$p = $this->tree;
while ($p) {
if ($data < $p->data) {
if(!$p->left){
$p->left = new Node($data);
return true;
}
$p = $p->left;
} elseif ($data > $p->data) {
if(!$p->right){
$p->right = new Node($data);
return true;
}
$p = $p->right;
} else {
return false;
}
}
}
四、二叉排序树的删除
二叉排序树的删除相对而言要复杂一些,需要分三种情况来处理:
- 第一种情况是,如果要删除的节点没有子节点,直接将该结点删除就可以。表现在PHP中就是将父节点中指向要删除节点的指针置为 null。
- 第二种情况是,如果要删除的节点只有一个子节点,只需要将父节点中对子结点指针,指向要删除节点的子节点就可以了。
- 第三种情况是,如果要删除的节点有两个子节点,需要找到这个节点的右子树中的最小节点(或者左子树中的最大节点),把它替换到要删除的节点上。然后再删除掉这个最小(最大)节点,因为最小(最大)节点肯定没有左(右)子节点。

二叉排序树的删除代码如下:
public function delete(int $data) {
if( !$this->tree ) {
return;
}
$p = $this->tree;
$pp = null;
while ($p && $data != $p->data) {
$pp = $p;
if($data < $p->data) {
$p = $p->left;
} elseif ($data > $p->data) {
$p = $p->right;
}
}
if($p == null) {
return;
}
if($p->left && $p->right) {
$minP = $p->right;
$minPP = null;
while ($minP->left) {
$minPP = $minP;
$minP = $minP->left;
}
$p->data = $minP->data;
$p = $minP;
$pp = $minPP;
}
$child = null;
if ($p->left) {
$child = $p->left;
} elseif ($p->right) {
$child = $p->right;
}
if (!$pp) {
$this->tree = $child;
} elseif ($pp->left == $p){
$pp->left = $child;
} else {
$pp->right = $child;
}
}
五、测试及结果
测试完整代码如下:
<?php
/**
* BinarySortedTree.php
* Created on 2019/4/27 11:03
* Created by Wilin
*/ include "Node.php";
include "../Traverse.php"; class BinarySortedTree
{
private $tree; public function getTree() {
return $this->tree;
} public function find(int $data) {
$p = $this->tree;
while ($p) {
if ($data < $p->data) {
$p = $p->left;
} elseif ($data > $p->data) {
$p = $p->right;
} else {
return $p;
}
}
return null;
} public function insert(int $data) {
if (!$this->tree) {
$this->tree = new Node($data);
return true;
}
$p = $this->tree;
while ($p) {
if ($data < $p->data) {
if(!$p->left){
$p->left = new Node($data);
return true;
}
$p = $p->left;
} elseif ($data > $p->data) {
if(!$p->right){
$p->right = new Node($data);
return true;
}
$p = $p->right;
} else {
return false;
}
}
} public function delete(int $data) {
if( !$this->tree ) {
return;
} $p = $this->tree;
$pp = null; while ($p && $data != $p->data) {
$pp = $p;
if($data < $p->data) {
$p = $p->left;
} elseif ($data > $p->data) {
$p = $p->right;
}
} if($p == null) {
return;
} if($p->left && $p->right) {
$minP = $p->right;
$minPP = null;
while ($minP->left) {
$minPP = $minP;
$minP = $minP->left;
}
$p->data = $minP->data;
$p = $minP;
$pp = $minPP;
} $child = null;
if ($p->left) {
$child = $p->left;
} elseif ($p->right) {
$child = $p->right;
} if (!$pp) {
$this->tree = $child;
} elseif ($pp->left == $p){
$pp->left = $child;
} else {
$pp->right = $child;
}
}
} $tree = new BinarySortedTree();
$tree->insert(1);
$tree->insert(3);
$tree->insert(4);
$tree->insert(6);
$tree->insert(6);
print "查找4=============\n";
print_r($tree->find(4));
print "遍历==============\n";
midOrderTraverse($tree->getTree());
print "删除4=============\n";
$tree->delete(4);
print "查找4=============\n";
print_r($tree->find(4));
print "遍历==============\n";
midOrderTraverse($tree->getTree());
结果如下:
E:\www\tree\1>php BinarySortedTree.php
查找4=============
Node Object
(
[data] => 4
[left] =>
[right] => Node Object
(
[data] => 6
[left] =>
[right] =>
) )
遍历==============
1
3
4
6
删除4=============
查找4=============
遍历==============
1
3
6
二叉排序树详解——PHP代码实现的更多相关文章
- Python - 元组(tuple) 详解 及 代码
元组(tuple) 详解 及 代码 本文地址: http://blog.csdn.net/caroline_wendy/article/details/17290967 元组是存放任意元素集合,不能修 ...
- Python - 字典(dict) 详解 及 代码
字典(dict) 详解 及 代码 本文地址: http://blog.csdn.net/caroline_wendy/article/details/17291329 字典(dict)是表示映射的数据 ...
- 深度学习之卷积神经网络(CNN)详解与代码实现(一)
卷积神经网络(CNN)详解与代码实现 本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/10430073.html 目 ...
- C#的String.Split 分割字符串用法详解的代码
代码期间,把代码过程经常用的内容做个珍藏,下边代码是关于C#的String.Split 分割字符串用法详解的代码,应该对码农们有些用途. 1) public string[] Split(params ...
- laravel 框架配置404等异常页面的方法详解(代码示例)
本篇文章给大家带来的内容是关于laravel 框架配置404等异常页面的方法详解(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 在Laravel中所有的异常都由Handl ...
- Android java程序员必备技能,集合与数组中遍历元素,增强for循环的使用详解及代码
Android java程序员必备技能,集合与数组中遍历元素, 增强for循环的使用详解及代码 作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 For ...
- UIWebView用法详解及代码分享
今天我们来详细UIWebView用法.UIWebView是iOS内置的浏览器控件,可以浏览网页.打开文档等 能够加载html/htm.pdf.docx.txt等格式的文件. 用UIWebView我们就 ...
- 【转载】 深度学习之卷积神经网络(CNN)详解与代码实现(一)
原文地址: https://www.cnblogs.com/further-further-further/p/10430073.html ------------------------------ ...
- 设计模式相关面试问题-Builder基础详解与代码解读
java的builder模式详解: 概念:建造者模式是较为复杂的创建型模式,它将客户端与多含多个组成部分(或部件)的复杂对象的创建过程分离. 使用场景:当构造一个对象需要很多参数的时候,并且参数的个数 ...
随机推荐
- 关于SkyApm测试部署。
这个是skyapm的github : https://github.com/SkyAPM/SkyAPM-dotnet 它依赖于skywalking . 我是用docker去部署的.因为这样我的系统会干 ...
- NIO Channel SocketChannel ServerSocketChannel
ServerSocketChannel: ServerSocketChannel是一个基于通道的socket监听器.它同我们所熟悉的java.net.ServerSocket执行相同的基本任务,不过它 ...
- Scala函数柯里化(Currying or Curry)
柯里化(Currying) 把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术. 简单的实现如下: scala> def ...
- hadoop综合
对CSV文件进行预处理生成无标题文本文件,将爬虫大作业产生的csv文件上传到HDFS 首先,我们需要在本地中创建一个/usr/local/bigdatacase/dataset文件夹,具体的步骤为: ...
- codeDecodeError ascii codec can't decode byte 0xe2 in position 44 ordinal not in range(128)
- ireport初接触
我用的版本5.6.0 @官网下载地址 下载安装@参考博客龙凌云端,着重留意:在windows下使用,只下载iReport-5.6.0-windows-installer.exe就行了 安装后配置环境变 ...
- django 表操作
添加表纪录 # Create your models here. class Book(models.Model): id = models.AutoField(primary_key=True) t ...
- [图片问答]lodop注册相关
相关博文:LODOP和C-LODOP注册与角色等简短问答[增强版]由于其他博文要么图片太花哨(PS做的所以太花哨),要么文字太啰嗦,所以做了简短问答的图片,更简洁直观方便.1.该购买哪种LODOP注册 ...
- FormsAuthentication使用指南,实现登录
一般情况下,在我们做访问权限管理的时候,会把用户的正确登录后的基本信息保存在Session中,以后用户每次请求页面或接口数据的时候,拿到Session中存储的用户基本信息,查看比较他有没有登录和能否访 ...
- [LeetCode] 207. Course Schedule 课程安排
There are a total of n courses you have to take, labeled from 0 to n - 1. Some courses may have prer ...