您好,登錄后才能下訂單哦!
這篇文章主要介紹PHP如何實現二叉樹深度優先遍歷和廣度優先遍歷,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
前言:
深度優先遍歷:對每一個可能的分支路徑深入到不能再深入為止,而且每個結點只能訪問一次。要特別注意的是,二叉樹的深度優先遍歷比較特殊,可以細分為先序遍歷、中序遍歷、后序遍歷。具體說明如下:
前序遍歷:根節點->左子樹->右子樹
中序遍歷:左子樹->根節點->右子樹
后序遍歷:左子樹->右子樹->根節點
廣度優先遍歷:又叫層次遍歷,從上往下對每一層依次訪問,在每一層中,從左往右(也可以從右往左)訪問結點,訪問完一層就進入下一層,直到沒有結點可以訪問為止。
例如對于一下這棵樹:
深度優先遍歷:
前序遍歷:10 8 7 9 12 11 13
中序遍歷:7 8 9 10 11 12 13
后序遍歷:7 9 8 11 13 12 10
廣度優先遍歷:
層次遍歷:10 8 12 7 9 11 13
二叉樹的深度優先遍歷的非遞歸的通用做法是采用棧,廣度優先遍歷的非遞歸的通用做法是采用隊列。
深度優先遍歷:
1、前序遍歷:
/** * 前序遍歷(遞歸方法) */ private function pre_order1($root) { if (!is_null($root)) { //這里用到常量__FUNCTION__,獲取當前函數名,好處是假如修改函數名的時候,里面的實現不用修改 $function = __FUNCTION__; echo $root->key . " "; $this->$function($root->left); $this->$function($root->right); } } /** * 前序遍歷(非遞歸方法) * 因為當遍歷過根節點之后還要回來,所以必須將其存起來。考慮到后進先出的特點,選用棧存儲。 */ private function pre_order2($root) { // $stack = new splstack(); // $stack->push($root); // while(!$stack->isEmpty()){ // $node = $stack->pop(); // echo $node->key.' '; // if(!is_null($node->right)){ // $stack->push($node->right); // } // if(!is_null($node->left)){ // $stack->push($node->left); // } // } if (is_null($root)) { return; } $stack = new splstack(); $node = $root; while (!is_null($node) || !$stack->isEmpty()) { while (!is_null($node)) { //只要結點不為空就應該入棧保存,與其左右結點無關 $stack->push($node); echo $node->key . ' '; $node = $node->left; } $node = $stack->pop(); $node = $node->right; } } //前序遍歷 public function PreOrder() { // 所在對象中的tree屬性保存了一個樹的引用 // $this->pre_order1($this->tree->root); $this->pre_order2($this->tree->root); }
說明:1、我將所有的遍歷方法都封裝在一個類 traverse 里面了。2、pre_order2方法中,在使用棧的過程中,我使用的是PHP標準庫SPL提供的splstack,如果你們習慣使用數組的話,可以使用 array_push()
和array_pop()
模擬實現。
2、中序遍歷:
/** * 中序遍歷(遞歸方法) */ private function mid_order1($root) { if (!is_null($root)) { $function = __FUNCTION__; $this->$function($root->left); echo $root->key . " "; $this->$function($root->right); } } /** * 中序遍歷(非遞歸方法) * 因為當遍歷過根節點之后還要回來,所以必須將其存起來。考慮到后進先出的特點,選用棧存儲。 */ private function mid_order2($root) { if (is_null($root)) { return; } $stack = new splstack(); $node = $root; while (!is_null($node) || !$stack->isEmpty()) { while (!is_null($node)) { $stack->push($node); $node = $node->left; } $node = $stack->pop(); echo $node->key . ' '; $node = $node->right; } } //中序遍歷 public function MidOrder() { // $this->mid_order1($this->tree->root); $this->mid_order2($this->tree->root); }
3、后序遍歷:
/** * 后序遍歷(遞歸方法) */ private function post_order1($root) { if (!is_null($root)) { $function = __FUNCTION__; $this->$function($root->left); $this->$function($root->right); echo $root->key . " "; } } /** * 后序遍歷(非遞歸方法) * 因為當遍歷過根節點之后還要回來,所以必須將其存起來。考慮到后進先出的特點,選用棧存儲。 * 由于在訪問了左子節點后怎么跳到右子節點是難點,這里使用一個標識lastVisited來標識上一次訪問的結點 */ private function post_order2($root) { if (is_null($root)) { return; } $node = $root; $stack = new splstack(); //保存上一次訪問的結點引用 $lastVisited = NULL; $stack->push($node); while(!$stack->isEmpty()){ $node = $stack->top();//獲取棧頂元素但不彈出 if(($node->left == NULL && $node->right == NULL) || ($node->right == NULL && $lastVisited == $node->left) || ($lastVisited == $node->right)){ echo $node->key.' '; $lastVisited = $node; $stack->pop(); }else{ if($node->right){ $stack->push($node->right); } if($node->left){ $stack->push($node->left); } } } } //后序遍歷 public function PostOrder() { // $this->post_order1($this->tree->root); $this->post_order2($this->tree->root); }
廣度優先遍歷:
1、層次遍歷:
/** * 層次遍歷(遞歸方法) * 由于是按層逐層遍歷,因此傳遞樹的層數 */ private function level_order1($root,$level){ if($root == NULL || $level < 1){ return; } if($level == 1){ echo $root->key.' '; return; } if(!is_null($root->left)){ $this->level_order1($root->left,$level - 1); } if(!is_null($root->right)){ $this->level_order1($root->right,$level - 1); } } /** * 層次遍歷(非遞歸方法) * 每一層從左向右輸出 元素需要儲存有先進先出的特性,所以選用隊列存儲。 */ private function level_order2($root){ if(is_null($root)){ return; } $node = $root; //利用隊列實現 // $queue = array(); // array_push($queue,$node); // // while(!is_null($node = array_shift($queue))){ // echo $node->key.' '; // if(!is_null($node->left)){ // array_push($queue,$node->left); // } // if(!is_null($node->right)){ // array_push($queue,$node->right); // } // } $queue = new splqueue(); $queue->enqueue($node); while(!$queue->isEmpty()){ $node = $queue->dequeue(); echo $node->key.' '; if (!is_null($node->left)) { $queue->enqueue($node->left); } if (!is_null($node->right)) { $queue->enqueue($node->right); } } } //層次遍歷 public function LevelOrder(){ // $level = $this->getdepth($this->tree->root); // for($i = 1;$i <= $level;$i ++){ // $this->level_order1($this->tree->root,$i); // } $this->level_order2($this->tree->root); } //獲取樹的層數 private function getdepth($root){ if(is_null($root)){ return 0; } $left = getdepth($root -> left); $right = getdepth($root -> right); $depth = ($left > $right ? $left : $right) + 1; return $depth; }
說明:level_order2方法中,在使用隊列的過程中,我使用的是PHP標準庫SPL提供的splqueue,如果你們習慣使用數組的話,可以使用 array_push()
和array_shift()
模擬實現。
使用:
現在我們來看看客戶端代碼:
class Client { public static function Main() { try { //實現文件的自動加載 function autoload($class) { include strtolower($class) . '.php'; } spl_autoload_register('autoload'); $arr = array(10, 8, 12, 7, 9, 11, 13); $tree = new Bst(); // $tree = new Avl(); // $tree = new Rbt(); $tree->init($arr); $traverse = new traverse($tree); $traverse->PreOrder(); // $traverse->MidOrder(); // $traverse->PostOrder(); // $traverse->LevelOrder(); } catch (Exception $e) { echo $e->getMessage(); } } } CLient::Main();
以上是“PHP如何實現二叉樹深度優先遍歷和廣度優先遍歷”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。