二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。

一、定义

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:

  • 若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
  • 左、右子树也分别为二叉排序树;

如果按照中序遍历一个二叉排序树得到的是一个从小到大排好序的数据集。构造一棵二叉排序树的目的,并不是为了排序,而是为了提高查找和插入删除关键字的速度。不管怎么说,在一个有序数据集上的查找,速度总是要快于无序的数据集的,而二叉排序树这种非线性的结构,也有利于插入和删除的实现。

二、二叉排序树的查找

首先构建节点类,如下

  1. <?php
  2. /**
  3. * Node.php
  4. * Created on 2019/4/27 9:09
  5. * Created by Wilin
  6. */
  7.  
  8. class Node {
  9. public $data;
  10. public $left = null;
  11. public $right = null;
  12.  
  13. public function __construct($data) {
  14. $this->data = $data;
  15. }
  16. }

中序遍历方法如下

  1. <?php
  2. /**
  3. * Traverse.php
  4. * Created on 2019/4/27 11:10
  5. * Created by Wilin
  6. */
  7. function midOrderTraverse($tree) {
  8. if($tree == null) {
  9. return;
  10. }
  11.  
  12. midOrderTraverse($tree->left);
  13. printf("%s\n", $tree->data);
  14. midOrderTraverse($tree->right);
  15. }

二叉排序树类基本结构如下:

  1. <?php
  2. /**
  3. * BinarySortedTree.php
  4. * Created on 2019/4/27 11:03
  5. * Created by Wilin
  6. */
  7.  
  8. include "Node.php";
  9. include "../Traverse.php";
  10.  
  11. class BinarySortedTree
  12. {
  13. private $tree;
  14.  
  15. public function getTree() {
  16. return $this->tree;
  17. }
  18. }

下面开始往二叉排序树中添加查找方法。

查找步骤:

  • 若根结点的关键字值等于查找的关键字,成功。
  • 否则,若小于根结点的关键字值,递归查左子树。
  • 若大于根结点的关键字值,递归查右子树。
  • 若子树为空,查找不成功。

根据该步骤,编写出如下查找代码

  1. public function find(int $data) {
  2. $p = $this->tree;
  3. while ($p) {
  4. if ($data < $p->data) {
  5. $p = $p->left;
  6. } elseif ($data > $p->data) {
  7. $p = $p->right;
  8. } else {
  9. return $p;
  10. }
  11. }
  12. return null;
  13. }

三、二叉排序树的插入

插入步骤

  • 首先执行查找算法,找出被插结点的父亲结点。
  • 判断被插结点是其父亲结点的左、右儿子。将被插结点作为叶子结点插入。
  • 若二叉树为空。则首先单独生成根结点。

注意:新插入的结点总是叶子结点。

根据插入步骤,编写出如下插入代码

  1. public function insert(int $data) {
  2. if (!$this->tree) {
  3. $this->tree = new Node($data);
  4. return true;
  5. }
  6. $p = $this->tree;
  7. while ($p) {
  8. if ($data < $p->data) {
  9. if(!$p->left){
  10. $p->left = new Node($data);
  11. return true;
  12. }
  13. $p = $p->left;
  14. } elseif ($data > $p->data) {
  15. if(!$p->right){
  16. $p->right = new Node($data);
  17. return true;
  18. }
  19. $p = $p->right;
  20. } else {
  21. return false;
  22. }
  23. }
  24. }

四、二叉排序树的删除

二叉排序树的删除相对而言要复杂一些,需要分三种情况来处理:

  • 第一种情况是,如果要删除的节点没有子节点,直接将该结点删除就可以。表现在PHP中就是将父节点中指向要删除节点的指针置为 null。
  • 第二种情况是,如果要删除的节点只有一个子节点,只需要将父节点中对子结点指针,指向要删除节点的子节点就可以了。
  • 第三种情况是,如果要删除的节点有两个子节点,需要找到这个节点的右子树中的最小节点(或者左子树中的最大节点),把它替换到要删除的节点上。然后再删除掉这个最小(最大)节点,因为最小(最大)节点肯定没有左(右)子节点。

二叉排序树的删除代码如下:

  1. public function delete(int $data) {
  2. if( !$this->tree ) {
  3. return;
  4. }
  5.  
  6. $p = $this->tree;
  7. $pp = null;
  8.  
  9. while ($p && $data != $p->data) {
  10. $pp = $p;
  11. if($data < $p->data) {
  12. $p = $p->left;
  13. } elseif ($data > $p->data) {
  14. $p = $p->right;
  15. }
  16. }
  17.  
  18. if($p == null) {
  19. return;
  20. }
  21.  
  22. if($p->left && $p->right) {
  23. $minP = $p->right;
  24. $minPP = null;
  25. while ($minP->left) {
  26. $minPP = $minP;
  27. $minP = $minP->left;
  28. }
  29. $p->data = $minP->data;
  30. $p = $minP;
  31. $pp = $minPP;
  32. }
  33.  
  34. $child = null;
  35. if ($p->left) {
  36. $child = $p->left;
  37. } elseif ($p->right) {
  38. $child = $p->right;
  39. }
  40.  
  41. if (!$pp) {
  42. $this->tree = $child;
  43. } elseif ($pp->left == $p){
  44. $pp->left = $child;
  45. } else {
  46. $pp->right = $child;
  47. }
  48. }

五、测试及结果

测试完整代码如下:

  1. <?php
  2. /**
  3. * BinarySortedTree.php
  4. * Created on 2019/4/27 11:03
  5. * Created by Wilin
  6. */
  7.  
  8. include "Node.php";
  9. include "../Traverse.php";
  10.  
  11. class BinarySortedTree
  12. {
  13. private $tree;
  14.  
  15. public function getTree() {
  16. return $this->tree;
  17. }
  18.  
  19. public function find(int $data) {
  20. $p = $this->tree;
  21. while ($p) {
  22. if ($data < $p->data) {
  23. $p = $p->left;
  24. } elseif ($data > $p->data) {
  25. $p = $p->right;
  26. } else {
  27. return $p;
  28. }
  29. }
  30. return null;
  31. }
  32.  
  33. public function insert(int $data) {
  34. if (!$this->tree) {
  35. $this->tree = new Node($data);
  36. return true;
  37. }
  38. $p = $this->tree;
  39. while ($p) {
  40. if ($data < $p->data) {
  41. if(!$p->left){
  42. $p->left = new Node($data);
  43. return true;
  44. }
  45. $p = $p->left;
  46. } elseif ($data > $p->data) {
  47. if(!$p->right){
  48. $p->right = new Node($data);
  49. return true;
  50. }
  51. $p = $p->right;
  52. } else {
  53. return false;
  54. }
  55. }
  56. }
  57.  
  58. public function delete(int $data) {
  59. if( !$this->tree ) {
  60. return;
  61. }
  62.  
  63. $p = $this->tree;
  64. $pp = null;
  65.  
  66. while ($p && $data != $p->data) {
  67. $pp = $p;
  68. if($data < $p->data) {
  69. $p = $p->left;
  70. } elseif ($data > $p->data) {
  71. $p = $p->right;
  72. }
  73. }
  74.  
  75. if($p == null) {
  76. return;
  77. }
  78.  
  79. if($p->left && $p->right) {
  80. $minP = $p->right;
  81. $minPP = null;
  82. while ($minP->left) {
  83. $minPP = $minP;
  84. $minP = $minP->left;
  85. }
  86. $p->data = $minP->data;
  87. $p = $minP;
  88. $pp = $minPP;
  89. }
  90.  
  91. $child = null;
  92. if ($p->left) {
  93. $child = $p->left;
  94. } elseif ($p->right) {
  95. $child = $p->right;
  96. }
  97.  
  98. if (!$pp) {
  99. $this->tree = $child;
  100. } elseif ($pp->left == $p){
  101. $pp->left = $child;
  102. } else {
  103. $pp->right = $child;
  104. }
  105. }
  106. }
  107.  
  108. $tree = new BinarySortedTree();
  109. $tree->insert(1);
  110. $tree->insert(3);
  111. $tree->insert(4);
  112. $tree->insert(6);
  113. $tree->insert(6);
  114. print "查找4=============\n";
  115. print_r($tree->find(4));
  116. print "遍历==============\n";
  117. midOrderTraverse($tree->getTree());
  118. print "删除4=============\n";
  119. $tree->delete(4);
  120. print "查找4=============\n";
  121. print_r($tree->find(4));
  122. print "遍历==============\n";
  123. midOrderTraverse($tree->getTree());

结果如下:

  1. E:\www\tree\1>php BinarySortedTree.php
  2. 查找4=============
  3. Node Object
  4. (
  5. [data] => 4
  6. [left] =>
  7. [right] => Node Object
  8. (
  9. [data] => 6
  10. [left] =>
  11. [right] =>
  12. )
  13.  
  14. )
  15. 遍历==============
  16. 1
  17. 3
  18. 4
  19. 6
  20. 删除4=============
  21. 查找4=============
  22. 遍历==============
  23. 1
  24. 3
  25. 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. 20189220 余超《Linux内核原理与分析》第一周作业

    实验一 Linux系统简介 通过实验一主要是学习到了Linux 的历史简介,linux与windows之间的区别,主要是免费和收费,软件和支持,安全性,使用习惯,可制定性,应用范畴等.linux具有稳 ...

  2. spring boot后端使用fastjson,错误代码415, 500

    $.post({ url: "/register", dataType: "json", contentType: "application/json ...

  3. Hadoop综合大作业1

    本次作业来源于:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/3363 一.课程评分标准: 分数组成: 考勤 10 平时作业 30 爬 ...

  4. modao账户

    chairman987@163.com 墨刀注册 p@ssw0rd OR 123456

  5. Devops(四):Docker 镜像管理

    参考 <Docker中上传镜像到docker hub中> <Docker 镜像管理> <通过容器提交镜像(docker commit)以及推送镜像(docker push ...

  6. cnetos7 搭建wordpress(apache+php+mariadb)

    .安装apache.php.php库 yum -y install httpd php php-mbstring php-pear 2.修改php配置文件地区 vim /etc/php.ini 在87 ...

  7. 纯CSS样式实现数字加减按钮的最佳方案

    前言: 对于数字加减按钮的实现,以前用过不少方案,诸如: 1.使用背景图片——这种效果比较好,缺点是样式控制有点复杂了,还需要使用图片: 2.直接使用“+”“-”——这种方法简单粗暴,最容易实现,缺点 ...

  8. oracle sequnece 介绍以及 监控

    ###sequnece 介绍 http://www.dba-oracle.com/t_rac_tuning_sequence_order_parameter.htm order by 可能会影响性能, ...

  9. [LeetCode] 875. Koko Eating Bananas 可可吃香蕉

    Koko loves to eat bananas.  There are N piles of bananas, the i-th pile has piles[i] bananas.  The g ...

  10. 【SSH进阶之路】Spring的IOC逐层深入——为什么要使用IOC[实例讲解](二)

    上篇博客[SSH进阶之路]Spring简介,搭建Spring环境——轻量级容器框架(一),我们简单的介绍了Spring的基本概念,并且搭建了两个版本的Spring开发环境,但是我们剩下了Spring最 ...