數據結構-PHP 二分搜索樹的層序遍歷(隊列實現)

​前面文章介紹了二分搜索樹的 前序遍歷中序遍歷後續遍歷,這篇文章主要介紹一下如何使用 隊列 實現二分搜索樹的 層序遍歷php

1.隊列

1.1 隊列的特色

  • 隊列(Queue) 是一種線性結構。
  • 只能從一端 tail(隊尾) 添加元素,從另一端 front(隊首) 取出元素。
  • 是一種 First In First Out(FIFO),即 先進先出 的結構。

1.2 隊列的圖示

1.3 鏈表

這是封裝好的一個鏈表類,能實現鏈表的基本功能:node

<?php
/**
 * 鏈表的實現
 * Class LinkedList
 */
class LinkedList
{
    private $dummyHead;
    private $size;
    /**
     * 初始化鏈表 null->null
     * LinkedList constructor.
     */
    public function __construct() {
        $this->dummyHead = new Node(null, null);
        $this->size = 0;
    }
    /**
     * 獲取鏈表大小
     * @return int
     */
    public function getSize(): int {
        return $this->size;
    }
    /**
     * 判斷鏈表是否爲空
     * @return bool
     */
    public function isEmpty(): bool {
        return $this->size == 0;
    }
    /**
     * 在鏈表的第 index 位置添加元素
     * @param int $index
     * @param $e
     */
    public function add(int $index, $e): void {
        if ($index < 0 || $index > $this->size) {
            echo "索引範圍錯誤";
            exit;
        }
        $prve = $this->dummyHead;
        for ($i = 0; $i < $index; $i++) {
            $prve = $prve->next;
        }
        //將上插入位置的上一個位置的 next 節點指向插入節點,插入節點的 next 節點信息指向原上節點的 next 節點
        $prve->next = new Node($e, $prve->next);
        $this->size++;
    }
    /**
     * 向鏈表開頭添加元素
     * @param $e
     */
    public function addFirst($e): void {
        $this->add(0, $e);
    }
    /**
     * 向鏈表末尾添加元素
     * @param $e
     */
    public function addLast($e): void {
        $this->add($this->size, $e);
    }
    /**
     * 獲取鏈表第 index 位置元素
     * @param $index
     */
    public function get($index) {
        if ($index < 0 || $index > $this->size) {
            echo "索引範圍錯誤";
            exit;
        }
        $node = $this->dummyHead;
        for ($i = 0; $i < $index + 1; $i++) {
            $node = $node->next;
        }
        return $node->e;
    }
    /**
     * 獲取鏈表第一個元素
     * @return mixed
     */
    public function getFirst() {
        return $this->get(0);
    }
    /**
     * 獲取鏈表最後一個元素
     * @return mixed
     */
    public function getLast() {
        return $this->get($this->size - 1);
    }
    /**
     * 修改鏈表中第 index 位置元素值
     * @param $index
     * @param $e
     */
    public function update($index, $e) {
        if ($index < 0 || $index > $this->size) {
            echo "索引範圍錯誤";
            exit;
        }
        $node = $this->dummyHead;
        for ($i = 0; $i < $index + 1; $i++) {
            $node = $node->next;
        }
        $node->e = $e;
    }
    /**
     * 判斷鏈表中是否存在某個元素
     * @param $e
     * @return bool
     */
    public function contains($e): bool {
        for ($node = $this->dummyHead->next; $node != null; $node = $node->next) {
            if ($node->e == $e) {
                return true;
            }
        }
        return true;
    }
    /**
     * 刪除鏈表中第 index 位置元素
     * @param $index
     */
    public function remove($index) {
        if ($index < 0 || $index > $this->size) {
            echo "索引範圍錯誤";
            exit;
        }
        if ($this->size == 0) {
            echo "鏈表已是空";
            exit;
        }
        $prve = $this->dummyHead;
        for ($i = 0; $i < $index; $i++) {
            $prve = $prve->next;
        }
        $node = $prve->next;
        $prve->next = $node->next;
        $this->size--;
        return $node->e;
    }
    /**
     * 刪除鏈表頭元素
     */
    public function removeFirst() {
       return $this->remove(0);
    }
    /**
     * 刪除鏈表末尾元素
     */
    public function removeLast() {
       return $this->remove($this->size - 1);
    }
    /**
     * 鏈表元素轉化爲字符串顯示
     * @return string
     */
    public function toString(): string {
        $str = "";
        for ($node = $this->dummyHead->next; $node != null; $node = $node->next) {
            $str .= $node->e . "->";
        }
        return $str . "null";
    }
}
class Node
{
    public $e;//節點元素
    public $next; //下個節點信息
    /**
     * 構造函數 設置節點信息
     * Node constructor.
     * @param $e
     * @param $next
     */
    public function __construct($e, $next) {
        $this->e = $e;
        $this->next = $next;
    }
}

1.4 隊列

這是經過帶 尾指針 鏈表實現的 隊列 類,它裏面有 入隊(enqueue) 方法和 出隊(dequque) 方法 :git

<?php
/**
 * 帶有尾指針的鏈表
 * Class LinkedListTail
 */
class QueueByLinkedList
{
    private $head; //鏈表頭部
    private $tail; //鏈表尾部
    private $size; //鏈表大小
    /**
     * 構造函數 初始化鏈表
     * QueueByLinkedList constructor.
     */
    public function __construct() {
        $this->head = null;
        $this->tail = null;
        $this->size = 0;
    }
    /**
     * 入隊操做
     * @param $e
     */
    public function enqueue($e): void {
        if ($this->tail == null) {
            $this->tail = $this->head = new Node($e, null);
        } else {
            $node = new Node($e, null);
            $this->tail->next = $node;
            $this->tail = $node;
        }
        $this->size++;
    }
    /**
     * 出隊操做
     * @return mixed
     */
    public function dequeue() {
        if ($this->size == 0) {
            return "隊列已是空的";
        }
        $node = $this->head;
        $this->head = $node->next;
        $this->size--;
        if ($node->next == null) {
            $this->tail = null;
        }
        return $node->e;
    }
    public function getFront() {
        if ($this->size == 0) {
            return "隊列已是空的";
        }
        return $this->head->e;
    }
    public function getSize() {
        return $this->size;
    }
    /**
     * 判斷隊列是否爲空
     * @return bool
     */
    public function isEmpty(): bool {
        return $this->size == 0;
    }
    public function toString() {
        $str = "";
        for ($node = $this->head; $node != null; $node = $node->next) {
            $str .= $node->e . "->";
        }
        $str .= "null";
        return $str;
    }
}
class Node
{
    public $e;//節點元素
    public $next; //下個節點信息
    /**
     * 構造函數 設置節點信息
     * Node constructor.
     * @param $e
     * @param $next
     */
    public function __construct($e, $next) {
        $this->e = $e;
        $this->next = $next;
    }
}

2.二分搜索樹層序遍歷

2.1 節點定義

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.2 原理說明

利用 隊列 的特色,從根節點開始,先把根節點入隊,而後出隊的時候須要判斷出隊元素是否爲空,若不爲空,先處理當前節點,而後先把 左兒子節點入隊,而後 右兒子 節點入隊,以此類推直到沒有兒子節點的時候就能夠繼續 出隊 下一個元素了,直到 隊列 爲空表示遍歷完畢,經過這種 隊列 的思想能夠達到 層序遍歷二分搜索樹 的目的。函數

Tips:若不爲空的節點沒有兒子節點,這裏實際處理它的兒子節點也會入棧  null

2.3 實現原理圖示

2.4 二分搜索樹層序遍歷

下面展現的都是部分代碼,須要結合以前的,層序遍歷 是按照節點深度一層一層的遍歷:ui

/**
     * 層序遍歷實現
     */
    public function tierTraversalByLinkedList() {
        $queue = new QueueByLinkedList();
        //將根節點入隊
        $queue->enqueue($this->root);
        //循環依次出隊
        $node = $queue->dequeue();
        do {
            if ($node != null) { //若出棧的當前節點不是空
                echo $node->e . "<br>"; //而後打印當前節點信息
                $queue->enqueue($node->left);//左兒子入隊
                $queue->enqueue($node->right);//右兒子入隊
            } else { //如果空
                echo "null<br>";
            }
            //繼續出隊
            $node = $queue->dequeue();
        } while (!$queue->isEmpty());
    }
Tips:若不爲空的節點沒有兒子節點,這裏實際處理它的兒子節點也會入棧  null

下面是打印結果: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->tierTraversalByLinkedList();
/**
打印輸出
45
30
55
25
35
50
65
15
27
31
null
48
null
60
68
null
null
null
null
null
null
null
null
null
null
null
 */
Tips:能夠看到打印輸出結果和預期一致。

代碼倉庫 :https://gitee.com/love-for-po...spa

掃碼關注愛因詩賢指針

相關文章
相關標籤/搜索