二叉排序树(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代码实现的更多相关文章

  1. Python - 元组(tuple) 详解 及 代码

    元组(tuple) 详解 及 代码 本文地址: http://blog.csdn.net/caroline_wendy/article/details/17290967 元组是存放任意元素集合,不能修 ...

  2. Python - 字典(dict) 详解 及 代码

    字典(dict) 详解 及 代码 本文地址: http://blog.csdn.net/caroline_wendy/article/details/17291329 字典(dict)是表示映射的数据 ...

  3. 深度学习之卷积神经网络(CNN)详解与代码实现(一)

    卷积神经网络(CNN)详解与代码实现 本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/10430073.html 目 ...

  4. C#的String.Split 分割字符串用法详解的代码

    代码期间,把代码过程经常用的内容做个珍藏,下边代码是关于C#的String.Split 分割字符串用法详解的代码,应该对码农们有些用途. 1) public string[] Split(params ...

  5. laravel 框架配置404等异常页面的方法详解(代码示例)

    本篇文章给大家带来的内容是关于laravel 框架配置404等异常页面的方法详解(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 在Laravel中所有的异常都由Handl ...

  6. Android java程序员必备技能,集合与数组中遍历元素,增强for循环的使用详解及代码

    Android java程序员必备技能,集合与数组中遍历元素, 增强for循环的使用详解及代码 作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 For ...

  7. UIWebView用法详解及代码分享

    今天我们来详细UIWebView用法.UIWebView是iOS内置的浏览器控件,可以浏览网页.打开文档等 能够加载html/htm.pdf.docx.txt等格式的文件. 用UIWebView我们就 ...

  8. 【转载】 深度学习之卷积神经网络(CNN)详解与代码实现(一)

    原文地址: https://www.cnblogs.com/further-further-further/p/10430073.html ------------------------------ ...

  9. 设计模式相关面试问题-Builder基础详解与代码解读

    java的builder模式详解: 概念:建造者模式是较为复杂的创建型模式,它将客户端与多含多个组成部分(或部件)的复杂对象的创建过程分离. 使用场景:当构造一个对象需要很多参数的时候,并且参数的个数 ...

随机推荐

  1. locust参数化(数据库取值)

    locust参数化(数据库取值) 基于上一篇参数化的梳理,本篇用另一种方法从数据库中取出这100个用户来登录 思路:在 TaskSet 中的 on_start 方法表示执行任务前的操作,可以将数据库取 ...

  2. CMU Database Systems - MVCC

    MVCC是一种用空间来换取更高的并发度的技术 对同一个对象不去update,而且记录下每一次的不同版本的值 存在不会消失,新值并不能抹杀原先的存在 所以update操作并不是对世界的真实反映,这是一种 ...

  3. 利用lsof命令查找已经删除的文件来释放磁盘空间

    测试环境一台服务器/目录空间使用率达到97%,但是通过du -sh *发现实际空间没用到那么多,初步怀疑,之前删除的文件,有运行中的进程一直占用,导致空间没有释放,如图通过du -sh *发现共实际使 ...

  4. 使用yarn代替npm作为node.js的模块管理器

    使用yarn代替npm作为node.js的模块管理器 转 https://www.jianshu.com/p/bfe96f89da0e     Fast, reliable, and secure d ...

  5. Node add Test1

    root_group->addChild(node22); osg::Vec3f vec3f1 = node22->getBound().center(); osg::NodePathLi ...

  6. latex怎样生成table字样和caption换行的表格

    \begin{table}  \caption{\newline The results of running algorithm parallel using MapReduce.} \hline  ...

  7. 【Java】Swagger快速入门

    Swagger 简介 Swagger 是一套基于 OpenAPI 规范构建的开源工具,可以帮助我们设计.构建.记录以及使用 Rest API.Swagger 主要包含了以下三个部分: Swagger ...

  8. ADB命令使用大法

    ​前言 Android开发调试工具ADB的使用.ADB(Android Debug Bridge)是Android SDK中的一个工具, 使用ADB可以直接操作管理Android模拟器或者真实的And ...

  9. 【超分辨率】- CVPR2019中SR论文导读与剖析

    CVPR2019超分领域出现多篇更接近于真实世界原理的低分辨率和高分辨率图像对应的新思路.具体来说,以前论文训练数据主要使用的是人为的bicubic下采样得到的,网络倾向于学习bicubic下采样的逆 ...

  10. Xcode UI界面调试神器-injectionIII

    App Store搜索injectionIII下载即可,免费的哟. 打开injectionIII,运行即可. - (BOOL)application:(UIApplication *)applicat ...