一、二叉樹的遍歷
以某種特定順序訪問樹中所有的節點稱為
樹的遍歷,遍歷二叉樹可分
深度優先遍歷和
廣度優先遍歷。
深度優先遍歷:對每一個可能的分支路徑深入到不能再深入為止,而且每個節點只能訪問一次。可以細分為
先序遍歷、
中序遍歷、
后序遍歷。
深度優先遍歷
|
先序遍歷
|
中序遍歷
|
后序遍歷
|
解釋
|
對任一子樹,先訪問根,然后遍歷其左子樹,最后遍歷其右子樹。
即根節點->左子樹->右子樹。
|
對任一子樹,先遍歷其左子樹,然后訪問根,最后遍歷其右子樹。
即左子樹->根節點->右子樹。
|
對任一子樹,先遍歷其左子樹,然后遍歷其右子樹,最后訪問根。
即左子樹->右子樹->根節點。
|
原則
|
①輸出根。
②訪問左子樹。【先訪問左子樹中的左子樹,再訪問左子樹中的右子樹。】直到訪問到葉子節點后輸出。
③訪問右子樹。【先訪問右子樹中的左子樹,再訪問右子樹中的右子樹。】直到訪問到葉子節點后輸出。
|
①訪問左子樹。【先訪問左子樹中的左子樹,再訪問左子樹中的右子樹。】直到訪問到葉子節點后輸出。
②輸出根。
③訪問右子樹。【先訪問右子樹中的左子樹,再訪問右子樹中的右子樹。】直到訪問到葉子節點后輸出。
|
①訪問左子樹。【先訪問左子樹中的左子樹,再訪問左子樹中的右子樹】。直到訪問到葉子節點后輸出。
②訪問右子樹。【先訪問右子樹中的左子樹,再訪問右子樹中的右子樹】。直到訪問到葉子節點后輸出。
③再返回訪問根,並輸出。
|
遍歷步驟
|
A作為根,先輸出A。
從A開始,先訪問A的左子樹。B為左子樹的根節點,輸出B。B的左子樹為D,輸出D。D無左右子樹,則看B的右子樹,為E,輸出E。E無左右子樹,則A的左子樹全部輸出完。
再訪問A的右子樹,C為右子樹的根節點,輸出C。C的左子樹為F,輸出F。F無左右子樹,且C無右子樹,A的右子樹全部輸出完。
|
A作為根。從A開始,先訪問A的左子樹。
B的左子樹為D,輸出D。D無左右子樹,則B的左子樹已訪問完,訪問並輸出B。再看B的右子樹,為E,輸出E。E無左右子樹,則A的左子樹全部輸出完,返回並輸出A。
同理,再看A的右子樹。
C的左子樹為F,輸出F。F無左右子樹,則C的左子樹已訪問完,返回並輸出C。C無右子樹,則A的右子樹全部輸出完。
|
先訪問A的左子樹。再訪問左子樹中的左子樹。即A的左子樹為B,再訪問B的左子樹D。D沒有左右子樹,輸出D。
然后訪問左子樹中的右子樹。即訪問B的右子樹E,E沒有左右子樹,輸出E。再輸出B。
然后訪問A的右子樹。再訪問右子樹中的左子樹。即A的右子樹為C,再訪問C的左子樹F。F沒有左右子樹,輸出F。
然后訪問右子樹中的右子樹。即訪問C的右子樹,C沒有右子樹,輸出C。再輸出A。
|
遍歷結果
|
A(BDE)(CF)
|
(DBE)A(FC)
|
(DEB)(FC)A
|
廣度優先遍歷:又叫層次遍歷,從上往下對每一層依次訪問,在每一層中,從左往右(也可以從右往左)訪問節點,訪問完一層就進入下一層,直到沒有節點訪問為止。
二、PHP用遞歸、非遞歸方式實現深度優先遍歷二叉樹(先序、中序、后序)
1、先序遍歷

<?php class Node { public $value; public $left; public $right; } class BT { // 非遞歸 // 前序遍歷 根節點→左子樹→右子樹 // 先訪問根節點,再遍歷左子樹,最后遍歷右子樹;並且在遍歷左右子樹時,仍需先遍歷根節點,然后訪問左子樹,最后遍歷右子樹 public function preOrder($root) { $stack = array(); array_push($stack, $root); while (!empty($stack)) { $center_node = array_pop($stack); echo $center_node->value . " "; // 先輸出根節點 if ($center_node->right != null) { array_push($stack, $center_node->right); // 壓入左子樹 } if ($center_node->left != null) { array_push($stack, $center_node->left); } } } // 遞歸 // 前序遍歷 public function pre_order($root) { if ($root != null) { echo $root->value . " "; // 根 if ($root->left != null) { $this->pre_order($root->left); //遞歸遍歷左樹 } if ($root->right != null) { $this->pre_order($root->right); //遞歸遍歷右樹 } } } } // 測試 $a = new Node(); $b = new Node(); $c = new Node(); $d = new Node(); $e = new Node(); $f = new Node(); $a->value = "A"; $b->value = "B"; $c->value = "C"; $d->value = "D"; $e->value = "E"; $f->value = "F"; $a->left = $b; $a->right = $c; $b->left = $d; $b->right = $e; $c->left = $f; $bst = new BT(); echo "----深度優先----"; echo "</br>"; echo "非遞歸--前序遍歷:"; $bst->preOrder($a); echo "</br>"; echo "遞歸--前序遍歷:"; $bst->pre_order($a); PHP用遞歸、非遞歸方式實現二叉樹的先序遍歷
2、中序遍歷

class Node { public $value; public $left; public $right; } class BT { // 非遞歸 // 中序遍歷 // 左子樹→根節點→右子樹 public function inOrder($root) { $stack = array(); $current_node = $root; while (!empty($stack) || $current_node != null) { while ($current_node != null) { array_push($stack, $current_node); $current_node = $current_node->left; } $current_node = array_pop($stack); echo $current_node->value . " "; $current_node = $current_node->right; } } // 遞歸 // 中序遍歷 public function in_order($root) { if ($root != null) { if ($root->left != null) { $this->in_order($root->left); // 遞歸遍歷左樹 } echo $root->value . " "; if ($root->right != null) { $this->in_order($root->right); // 遞歸遍歷右樹 } } } } // 測試 $a = new Node(); $b = new Node(); $c = new Node(); $d = new Node(); $e = new Node(); $f = new Node(); $a->value = "A"; $b->value = "B"; $c->value = "C"; $d->value = "D"; $e->value = "E"; $f->value = "F"; $a->left = $b; $a->right = $c; $b->left = $d; $b->right = $e; $c->left = $f; $bst = new BT(); echo "----深度優先----"; echo "</br>"; echo "非遞歸--中序遍歷:"; $bst->inOrder($a); echo "</br>"; echo "遞歸--中序遍歷:"; $bst->in_order($a); echo "</br>"; PHP用遞歸、非遞歸方式實現二叉樹的中序遍歷
3、后序遍歷

<?php class Node { public $value; public $left; public $right; } class BT { // 非遞歸 // 后序遍歷 左子樹→右子樹→根節點 // 先遍歷左子樹,然后遍歷右子樹,最后訪問根節點;同樣,在遍歷左右子樹的時候同樣要先遍歷左子樹,然后遍歷右子樹,最后訪問根節點 public function postOrder($root) { $stack = array(); $out_stack = array(); array_push($stack, $root); while (!empty($stack)) { $center_node = array_pop($stack); array_push($out_stack, $center_node); // 最先壓入根節點,最后輸出 if ($center_node->left != null) { array_push($stack, $center_node->left); } if ($center_node->right != null) { array_push($stack, $center_node->right); } } while (!empty($out_stack)) { $center_node = array_pop($out_stack); echo $center_node->value . " "; } } // 遞歸 // 后序遍歷 public function post_order($root) { if ($root != null) { if ($root->left != null) { $this->post_order($root->left); // 遞歸遍歷左樹 } if ($root->right != null) { $this->post_order($root->right); // 遞歸遍歷右樹 } echo $root->value . " "; // 根 } } } // 測試 $a = new Node(); $b = new Node(); $c = new Node(); $d = new Node(); $e = new Node(); $f = new Node(); $a->value = "A"; $b->value = "B"; $c->value = "C"; $d->value = "D"; $e->value = "E"; $f->value = "F"; $a->left = $b; $a->right = $c; $b->left = $d; $b->right = $e; $c->left = $f; $bst = new BT(); echo "----深度優先----"; echo "</br>"; echo "非遞歸--后序遍歷:"; $bst->postOrder($a); echo "</br>"; echo "遞歸--后序遍歷:"; $bst->post_order($a); echo "</br>"; PHP用遞歸、非遞歸方式實現二叉樹的后序遍歷
三、PHP用遞歸、非遞歸方式實現廣度優先遍歷二叉樹

<?php class Node { public $value; public $left; public $right; } class BT { // 非遞歸 public function levelOrder($root) { if ($root == null) { return; } $node = $root; $queue = array(); array_push($queue, $node); // 根節點入隊 while (!empty($queue)) { // 持續輸出節點,直到隊列為空 $node = array_shift($queue); // 隊首元素出隊 echo $node->value . " "; // 左節點先入隊 if ($node->left != null) { array_push($queue, $node->left); } // 然后右節點入隊 if ($node->right != null) { array_push($queue, $node->right); } } } // 遞歸 // 獲取樹的層數(最大深度) function getDepth($root) { if ($root == null) { // 節點為空 return 0; } if ($root->left == null && $root->right == null) { // 只有根節點 return 1; } $left_depth = $this->getDepth($root->left); $right_depth = $this->getDepth($root->right); return ($left_depth > $right_depth ? $left_depth : $right_depth) + 1; // return $left_depth > $right_depth ? ($left_depth + 1) : ($right_depth + 1); } public function level_order($root) { // 空樹或層級不合理 $depth = $this->getDepth($root); if ($root == null || $depth < 1) { return; } for ($i = 1; $i <= $depth; $i++) { $this->printTree($root, $i); } } public function printTree($root, $level) { // 空樹或層級不合理 if ($root == null || $level < 1) { return; } if ($level == 1) { echo $root->value; } $this->printTree($root->left, $level - 1); $this->printTree($root->right, $level - 1); } } // 測試 $a = new Node(); $b = new Node(); $c = new Node(); $d = new Node(); $e = new Node(); $f = new Node(); $a->value = "A"; $b->value = "B"; $c->value = "C"; $d->value = "D"; $e->value = "E"; $f->value = "F"; $a->left = $b; $a->right = $c; $b->left = $d; $b->right = $e; $c->left = $f; $bst = new BT(); echo "----廣度優先----"; echo "</br>"; echo "非遞歸:"; $bst->levelOrder($a); echo "</br>"; echo "遞歸:"; $bst->level_order($a); PHP用遞歸、非遞歸方式實現二叉樹的層次遍歷
原文:https://www.cnblogs.com/sunshineliulu/p/7775214.html