前面文章介紹了二分搜索樹的 前序遍歷
、中序遍歷
、後續遍歷
,這篇文章主要介紹一下如何使用 隊列
實現二分搜索樹的 層序遍歷
。php
隊列(Queue)
是一種線性結構。tail(隊尾)
添加元素,從另一端 front(隊首)
取出元素。這是封裝好的一個鏈表類,能實現鏈表的基本功能: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; } }
這是經過帶 尾指針
鏈表實現的 隊列
類,它裏面有 入隊(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.3 PHP 代碼定義節點 class Node { public $e; public $left = null; public $right = null; /** * 構造函數 初始化節點數據 * Node constructor. * @param $e */ public function __construct($e) { $this->e = $e; } }
利用 隊列
的特色,從根節點開始,先把根節點入隊
,而後出隊
的時候須要判斷出隊元素是否爲空,若不爲空,先處理當前節點,而後先把 左兒子
節點入隊,而後 右兒子
節點入隊,以此類推直到沒有兒子節點的時候就能夠繼續 出隊
下一個元素了,直到 隊列
爲空表示遍歷完畢,經過這種 隊列
的思想能夠達到 層序遍歷二分搜索樹
的目的。函數
Tips:若不爲空的節點沒有兒子節點,這裏實際處理它的兒子節點也會入棧
null
。
下面展現的都是部分代碼,須要結合以前的,層序遍歷
是按照節點深度一層一層的遍歷: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
掃碼關注愛因詩賢指針