1. 程式人生 > 程式設計 >資料結構之利用PHP實現二分搜尋樹

資料結構之利用PHP實現二分搜尋樹

前言

這篇文章是介紹 二叉樹 和 二分搜尋樹,然後通過 PHP 程式碼定義一下 二分搜尋樹 的節點,使用遞迴思想操作向二分搜尋樹新增元素,然後實現了遞迴判斷二分搜尋樹上是否包含某個元素,最後分別實現了前序遍歷、中序遍歷、後序遍歷 二分搜尋樹。

1.二叉樹

1.1 二叉樹圖示

資料結構之利用PHP實現二分搜尋樹

1.2 二叉樹節點定義

//二叉樹具有唯一根節點
class Node{
 $e; //節點元素
 $left; //左兒子
 $right;//右兒子
}

Tips:二叉樹每個節點最多有兩個兒子,每個節點最多有一個父親。

1.3 二叉樹的特點

  • 二叉樹具有天然的遞迴結構,每個節點的左兒子或右兒子也是 二叉樹。
  • 二叉樹不一定是滿的,可能只有左兒子或又兒子。
  • 一個節點或 NULL 也可以看做一個二叉樹。

2.二分搜尋樹

2.1 二分搜尋樹特點

  • 二分搜尋樹是二叉樹。
  • 每個節點的元素的值都要大於左兒子所有節點的值。
  • 每個節點的元素的值都要小於右兒子所有節點的值。
  • 每個子樹也是二分搜尋樹。
  • 二分搜尋樹查詢速度快。
  • 儲存的元素必須要有比較性。

2.2 二分搜尋樹圖示

資料結構之利用PHP實現二分搜尋樹

2.3 PHP 程式碼定義節點

class Node
{
 public $e;
 public $left = null;
 public $right = null;
 /**
  * 建構函式 初始化節點資料
  * Node constructor.
  * @param $e
  */
 public function __construct($e) {
  $this->e = $e;
 }
}

2.4 向二分搜尋樹新增元素

下面展示的的使用遞迴思想向二分搜尋樹新增元素,其中 add($e) 方法表示想二分搜尋樹新增元素 $e,recursionAdd(Node $root,$e) 是一個遞迴函式,表示使用遞歸向二分搜尋樹新增元素:

 /**
  * 向二分搜尋樹新增元素
  * @param $e
  */
 public function add($e) {
  $this->root = $this->recursionAdd($this->root,$e);
 }
 /**
  * 遞歸向二分搜尋樹新增元素
  * @param Node $root
  * @param $e
  */
 public function recursionAdd(Node $root,$e) {
  if ($root == null) { //若節點為空則新增元素 並且返回當前節點資訊
   $this->size++;
   $root = new Node($e);
  } elseif ($e < $root->e) { //若元素小於當前節點元素 則向左節點遞迴新增元素
   $root->left = $this->recursionAdd($root->left,$e);
  } elseif ($e > $root->e) { //若元素大於當前節點元素 則向右節點遞迴新增元素
   $root->right = $this->recursionAdd($root->right,$e);
  } //若元素等於當前節點元素 則什麼都不做
 }

Tips:這裡的二分搜尋樹不包含重複元素,如果想要包含重複元素,可以定義每個左兒子所有元素小於等於父親節點,或者每個節點右兒子所有節點元素大於等於父親節點。

2.5 查詢二分搜尋樹是否包含某個元素

下面展示的的使用遞迴思想查詢二分搜尋樹元素是否包含某個元素,其中 contains($e) 方法表示查詢二分搜尋樹是否包含元素 $e,recursionContains(Node $root,$e) 是一個遞迴函式,表示使用遞迴查詢二分搜尋樹元素:

 /**
  * 判斷二分搜尋樹是否包含某個元素
  * @param $e
  * @return bool
  */
 public function contains($e): bool {
  return $this->recursionContains($this->root,$e);
 }
 /**
  * 遞迴判斷二分搜尋樹是否包含某元素
  * @param $root
  * @param $e
  * @return bool
  */
 private function recursionContains(Node $root,$e): bool {
  if ($root == null) { //若當前節點為空 則表示不存在元素 $e
   return false;
  } elseif ($e == $root->e) { //若 $e 等於當前節點元素,則表示樹包含元素 $e
   return true;
  } elseif ($e < $root->e) { //若 $e 小於當前節點元素,則去左兒子樹遞迴查詢是否包含節點
   return $this->recursionContains($root->left,$e);
  } else { //若 $e 大於當前節點元素,則去右兒子樹遞迴查詢是否包含節點
   return $this->recursionContains($root->right,$e);
  }
 }

Tips:遞迴的時候會比較元素和節點的值,遞迴的時候判斷元素大小相當於 “指路”,最終指向到的位置就是判斷是否包含元素是否存在的依據。

2.6 二分搜尋樹前序遍歷

前序遍歷操作就是把所有節點都訪問一次,前序遍歷 是先訪問節點,再遞迴遍歷左兒子樹,然後再遞迴遍歷右兒子樹:

 /**
  * 前序遍歷
  */
 public function preTraversal() {
  $this->recursionPreTraversal($this->root,0);
 }
 /**
  * 前序遍歷的遞迴
  */
 public function recursionPreTraversal($root,$sign_num) {
  echo $this->getSign($sign_num);//列印深度
  if ($root == null) {
   echo "null<br>";
   return;
  }
  echo $root->e . "<br>"; //列印當前節點元素
  $this->recursionPreTraversal($root->left,$sign_num + 1);
  $this->recursionPreTraversal($root->right,$sign_num + 1);
 }

下面是列印結果:

<?php
require 'BinarySearchTree.php';
$binarySearchTree = new BinarySearchTree();
$binarySearchTree->add(45);
$binarySearchTree->add(30);
$binarySearchTree->add(55);
$binarySearchTree->add(25);
$binarySearchTree->add(35);
$binarySearchTree->add(50);
$binarySearchTree->add(65);
$binarySearchTree->add(15);
$binarySearchTree->add(27);
$binarySearchTree->add(31);
$binarySearchTree->add(48);
$binarySearchTree->add(60);
$binarySearchTree->add(68);
//下面是預期想要的結果
/**
* 45
* /
* 30 55
* / /
* 25 35 50 65
* / / / /
* 15 27 31 48 60 68
*
*/
$binarySearchTree->preTraversal();
/**
列印輸出
45
-----30
----------25
---------------15
--------------------null
--------------------null
---------------27
--------------------null
--------------------null
----------35
---------------31
--------------------null
--------------------null
---------------null
-----55
----------50
---------------48
--------------------null
--------------------null
---------------null
----------65
---------------60
--------------------null
--------------------null
---------------68
--------------------null
--------------------null
*/

Tips:可以看到列印輸出結果和預期一致。

2.7 二分搜尋樹中序遍歷

遍歷操作就是把所有節點都訪問一次,後序遍歷 是先遞迴遍歷右兒子樹,再訪問節點,然後再遞迴遍歷右兒子樹,最後的順序輸出結果是有序的:

 /**
  * 中序遍歷
  */
 public function midTraversal() {
  $this->recursionMidTraversal($this->root,0);
 }
 /**
  * 中序遍歷的遞迴
  */
 public function recursionMidTraversal($root,$sign_num) {
  if ($root == null) {
   echo $this->getSign($sign_num);//列印深度
   echo "null<br>";
   return;
  }
  $this->recursionMidTraversal($root->left,$sign_num + 1);
  echo $this->getSign($sign_num);//列印深度
  echo $root->e . "<br>";
  $this->recursionMidTraversal($root->right,$sign_num + 1);
 }

下面是列印結果:

<?php
require 'BinarySearchTree.php';
$binarySearchTree = new BinarySearchTree();
$binarySearchTree->add(45);
$binarySearchTree->add(30);
$binarySearchTree->add(55);
$binarySearchTree->add(25);
$binarySearchTree->add(35);
$binarySearchTree->add(50);
$binarySearchTree->add(65);
$binarySearchTree->add(15);
$binarySearchTree->add(27);
$binarySearchTree->add(31);
$binarySearchTree->add(48);
$binarySearchTree->add(60);
$binarySearchTree->add(68);
//下面是預期想要的結果
/**
* 45
* /
* 30 55
* / /
* 25 35 50 65
* / / / /
* 15 27 31 48 60 68
*
*/
$binarySearchTree->midTraversal();
/**
列印輸出
--------------------null
---------------15
--------------------null
----------25
--------------------null
---------------27
--------------------null
-----30
--------------------null
---------------31
--------------------null
----------35
---------------null
45
--------------------null
---------------48
--------------------null
----------50
---------------null
-----55
--------------------null
---------------60
--------------------null
----------65
--------------------null
---------------68
--------------------null
*/

Tips:可以看到列印輸出結果和預期一致,但是此時的遍歷順序變了,最後的順序輸出結果是有序的。

2.8 二分搜尋樹後序遍歷

遍歷操作就是把所有節點都訪問一次,後序遍歷 是先遞迴遍歷左兒子樹,然後再遞迴遍歷右兒子樹,再訪問節點:

 /**
  * 後序遍歷
  */
 public function rearTraversal() {
  $this->recursionRearTraversal($this->root,0);
 }
 /**
  * 後序遍歷的遞迴
  */
 public function recursionRearTraversal($root,$sign_num) {
  if ($root == null) {
   echo $this->getSign($sign_num);//列印深度
   echo "null<br>";
   return;
  }
  $this->recursionRearTraversal($root->left,$sign_num + 1);
  $this->recursionRearTraversal($root->right,$sign_num + 1);
  echo $this->getSign($sign_num);//列印深度
  echo $root->e . "<br>";
 }

下面是列印結果:

<?php
require 'BinarySearchTree.php';
$binarySearchTree = new BinarySearchTree();
$binarySearchTree->add(45);
$binarySearchTree->add(30);
$binarySearchTree->add(55);
$binarySearchTree->add(25);
$binarySearchTree->add(35);
$binarySearchTree->add(50);
$binarySearchTree->add(65);
$binarySearchTree->add(15);
$binarySearchTree->add(27);
$binarySearchTree->add(31);
$binarySearchTree->add(48);
$binarySearchTree->add(60);
$binarySearchTree->add(68);
//下面是預期想要的結果
/**
* 45
* /
* 30 55
* / /
* 25 35 50 65
* / / / /
* 15 27 31 48 60 68
*
*/
$binarySearchTree->rearTraversal();
/**
列印輸出
--------------------null
--------------------null
---------------15
--------------------null
--------------------null
---------------27
----------25
--------------------null
--------------------null
---------------31
---------------null
----------35
-----30
--------------------null
--------------------null
---------------48
---------------null
----------50
--------------------null
--------------------null
---------------60
--------------------null
--------------------null
---------------68
----------65
-----55
45
*/

程式碼倉庫 :https://gitee.com/love-for-po...

總結

到此這篇關於資料結構之利用PHP實現二分搜尋樹的文章就介紹到這了,更多相關PHP實現二分搜尋樹內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!