二叉排序树(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. NIO Channel SocketChannel ServerSocketChannel

    ServerSocketChannel: ServerSocketChannel是一个基于通道的socket监听器.它同我们所熟悉的java.net.ServerSocket执行相同的基本任务,不过它 ...

  2. elementui 走马灯图片自适应

    点击单元格后弹出对话框轮播图片,用Carousel 走马灯实现. 希望图片无论分辨率多少,都能在一屏内显示,这时就要用图片自适应. 图片外层容器,使用 flex 布局,设置对齐方式为主轴.交叉轴居中 ...

  3. TICK/TIGK运维栈安装运行 docker【中】

    InfluxDB docker search influxdb docker pull influxdb docker run -d -p 8086:8086 -v /var/lib/influxdb ...

  4. tar_ssh 配合下载文件(适合于带宽充足传输大量小文件场景)

    局域网网速快,但是当要传输大量小文件时倘若仍然使用scp,由于每个文件传输完毕都需要独立进行传输完毕的确认,这样就无法充分利用带宽.一方面等待确认时tcp窗口无法填满,另一方面文件传完之前确认也不会开 ...

  5. ISO/IEC 9899:2011 前言

    前言 1.ISO(国际标准组织)与IEC(国际电工技术委员会)为全世界标准形成了专门的系统.作为ISO或IEC成员的国家机构,通过由各自组织所建立的技术委员会来加入国际标准的开发,以处理特定领域的技术 ...

  6. 解决EasyDSS、EasyNVR流媒体RTMP、HLS(m3u8)、HTTP-FLV播放提示H5播放错误的问题

    背景介绍 EasyDSS流媒体解决方案提供的是一站式的转码.点播.直播.录像.检索.时移回放服务,它的出现极大地简化了开发和集成的工作,基于其强大的后台管理能力,支持多种特性需求,完全能够满足企业视频 ...

  7. MongoDB的局域网连接问题

    问题前两天在本机连接虚拟机的MongoDB,总是连接拒绝 上网百度了一堆,找到一些看似解释,实则不一定管用的玩意. 自己找到一个解法是改etc/mongodb.conf文件,把bindIp的127.0 ...

  8. Python3中strip()、lstrip()、rstrip()用法详解

    Python中有三个去除头尾字符.空白符的函数,它们依次为: strip: 用来去除头尾字符.空白符(包括\n.\r.\t.' ',即:换行.回车.制表符.空格) lstrip:用来去除开头字符.空白 ...

  9. 学习数据结构Day4

    链表 之前看过了动态数组,栈和队列,虽然我们把第一个叫做动态数组,但是,他们的底层实质上还是静态数组.靠 resize来实现动态数组.而链表是真正的数据结构 链表需要一个节点. 数据存储在链表中 相当 ...

  10. Java学习关注

    1.不去上课: 内部类的继承: https://blog.csdn.net/ruidianbaihuo/article/details/102092256 2.Matrix海 子 http://www ...