二叉排序树(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. Prometheus监控神技--自动发现配置

    一.自动发现类型 在上一篇文中留了一个坑: 监控某个statefulset服务的时候,我在service文件中定义了个EP,然后把pod的ip写死在配置文件中,这样,当pod重启后,IP地址变化,就监 ...

  2. Web前端开发规范 之html命名规范

    1.文件名称命名规则 统一用小写的英文字母.数字和下划线,不得包含汉字空格和特殊符号 2.索引文件命名 一般用index为名字  如index.html  index.jsp 3.各子页面的命名规则 ...

  3. 【转】使用fastboot命令刷机流程详解

    一.Fastboot是什么? 1.1 首先介绍Recovery模式(卡刷) 在系统进行定制时,编译系统会编译出一份ZIP的压缩包,里面是一些系统分区镜像,提供给客户进行手动升级.恢复系统.需要提前将压 ...

  4. Docker 安装 MySQL 并实现远程连接

    获取 MySQL 镜像 docker pull mysql:5.6 查看镜像列表 docker images 启动 MySQL 镜像 docker run -itd -P mysql:5.6 bash ...

  5. win10 启动后会自动恢复上次关机前的应用

    转载:https://www.v2ex.com/t/425101

  6. [LeetCode] 741. Cherry Pickup 捡樱桃

    In a N x N grid representing a field of cherries, each cell is one of three possible integers. 0 mea ...

  7. react前端模版Material-UI.类似于antd/bootstrap

    Material-UI Material-UI是一个实现了Google's Material Design设计规范的react组件库,开箱即用,使用它可以快速搭建出赏心悦目的应用界面. 文档 各种模版 ...

  8. SOC中的DMIPS_GFLOPS_GMACS的含义

    l  DMIPS全称叫Dhrystone MIPS 这项测试是用来计算同一秒内系统的处理能力,它的单位以百万来计算,也就是(MIPS) 上面的意思也就是,这个处理器测整数计算能力为(200*100万) ...

  9. 腾讯的网站如何检测到你的 QQ 已经登录?

    转:http://www.lovelucy.info/tencent-sso.html 在 QQ 已经登录的情况下,手动输入网址打开 QQ 邮箱 或者 QQ 空间 等腾讯网站,可以看到网页已经检测到本 ...

  10. 16 JQuery---JavaScript框架

    1.JQuery概念一个JavaScript框架.简化JS开发JQuery是一个快速.简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScr ...