前面寫了一篇的文章,實現的方法是用的遞歸思想遍歷,這篇文章主要介紹一下如何使用 壓棧
的思想來遍歷二分搜索樹。php
爲了更好的結合壓棧的思想,下面先來介紹一下 棧
數據結構的知識:node
入棧(push)
、出棧(pop)
、查看棧頂(peek)
。鏈表
數據結構實現的 棧
,在 棧頂
會有一個 棧頂指針
。棧
這種數據結構的應用舉例,如:能夠實現 撤銷(undo)
、程序的調用(系統棧)
這是封裝好的一個鏈表類,能實現鏈表的基本功能:git
<?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; } }
這是一個封裝好的 棧(Stack)
,經過實例化 鏈表類(LinkedList)
實現了入棧(push)和 出棧(pop),還有查看棧頂(peek)
:數組
<?php require 'LinkedList.php'; class StackByLinkedList { //鏈表類對象,用於存放棧元素 protected $array = null; /** * 構造函數 定義棧的容量 * ArrayStruct constructor. * @param int $capacity */ public function __construct() { $this->array = new LinkedList(); } /** * 獲取棧大小 * @return int */ public function getSize(): int { return $this->array->getSize(); } /** * 判斷棧是否爲空 * @return bool */ public function isEmpty(): bool { return $this->array->isEmpty(); } /** * 元素入棧 */ public function push($e): void { $this->array->addFirst($e); } /** * 出棧 * @return mixed */ public function pop() { return $this->array->removeFirst(); } /** * 查看棧頂元素 * @return mixed */ public function peek() { return $this->array->getFirst(); } /** * 將棧數組轉化爲字符串 * @return string */ public function toString(): string { return $this->array->toString(); } }
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
。
下面展現的都是部分代碼,須要結合以前的《數據結構-PHP 實現二分搜索樹》,前序遍歷操做就是把全部節點都訪問一次,前序遍歷
是先訪問節點,再遍歷左兒子樹,而後再遍歷右兒子樹,要想達到這種效果,對於每一個節點都是先處理當前節點
,而後入棧右兒子
,最後入棧左兒子
,若出棧元素爲空,打印 null
以後繼續出棧:函數
Tips:若不爲空的節點沒有兒子節點,這裏實際處理它的兒子節點也會入棧
null
。
/** * 前序遍歷壓棧實現 */ public function preTraversalByStack() { $stack = new StackByLinkedList(); //將根節點壓入棧 $stack->push($this->root); //循環依次出棧 $node = $stack->pop(); do { if ($node != null) { //若出棧的當前節點不是空 echo $node->e . "<br>"; //先打印當前節點信息 //先入棧右兒子 $stack->push($node->right); //而後入棧左兒子 $stack->push($node->left); } else { //如果空 echo "null<br>"; } //繼續出棧 $node = $stack->pop(); } while (!$stack->isEmpty()); }
下面是打印結果:ui
<?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->preTraversalByStack(); /** 打印輸出 45 30 25 15 null null 27 null null 35 31 null null null */
Tips:能夠看到打印輸出結果和預期一致,而且和以前遞歸實現的方式一致,對於中序遍歷
、後續遍歷
來講具體實現邏輯比前序遍歷
要複雜一些。
代碼倉庫 :https://gitee.com/love-for-po...this
掃碼關注愛因詩賢spa