數據結構-PHP 實現二分搜索樹

這篇文章是介紹 二叉樹 和 二分搜索樹,而後經過 PHP 代碼定義一下 二分搜索樹 的節點,使用遞歸思想操做向二分搜索樹添加元素,而後實現了遞歸判斷二分搜索樹上是否包含某個元素,最後分別實現了前序遍歷中序遍歷後序遍歷 二分搜索樹。php

1.二叉樹

1.1 二叉樹圖示

1.2 二叉樹節點定義

//二叉樹具備惟一根節點
class Node{
    $e; //節點元素
    $left; //左兒子
    $right;//右兒子
}
Tips:二叉樹每一個節點最多有兩個兒子,每一個節點最多有一個父親。

1.3 二叉樹的特色

  • 二叉樹具備自然的遞歸結構,每一個節點的左兒子或右兒子也是 二叉樹
  • 二叉樹不必定是滿的,可能只有左兒子或又兒子。
  • 一個節點或 NULL 也能夠看作一個二叉樹。

2.二分搜索樹

2.1 二分搜索樹特色

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

2.2 二分搜索樹圖示

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) 方法表示想二分搜索樹添加元素 $erecursionAdd(Node $root, $e) 是一個遞歸函數,表示使用遞歸向二分搜索樹添加元素:git

/**
     * 向二分搜索樹添加元素
     * @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) 方法表示查詢二分搜索樹是否包含元素 $erecursionContains(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 二分搜索樹前序遍歷

前序遍歷操做就是把全部節點都訪問一次,前序遍歷 是先訪問節點,再遞歸遍歷左兒子樹,而後再遞歸遍歷右兒子樹:ui

/**
     * 前序遍歷
     */
    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);
    }

下面是打印結果:this

<?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 二分搜索樹中序遍歷

遍歷操做就是把全部節點都訪問一次,後序遍歷 是先遞歸遍歷右兒子樹,再訪問節點,而後再遞歸遍歷右兒子樹,最後的順序輸出結果是有序的spa

/**
     * 中序遍歷
     */
    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);
    }

下面是打印結果:code

<?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 二分搜索樹後序遍歷

遍歷操做就是把全部節點都訪問一次,後序遍歷 是先遞歸遍歷左兒子樹,而後再遞歸遍歷右兒子樹,再訪問節點:blog

/**
     * 後序遍歷
     */
    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...ip

掃碼關注愛因詩賢

相關文章
相關標籤/搜索