數據結構與算法之PHP實現二叉樹的遍歷


一、二叉樹的遍歷

以某種特定順序訪問樹中所有的節點稱為 樹的遍歷,遍歷二叉樹可分 深度優先遍歷廣度優先遍歷
深度優先遍歷:對每一個可能的分支路徑深入到不能再深入為止,而且每個節點只能訪問一次。可以細分為 先序遍歷、 中序遍歷、 后序遍歷。
深度優先遍歷
先序遍歷
中序遍歷
后序遍歷
解釋
對任一子樹,先訪問根,然后遍歷其左子樹,最后遍歷其右子樹。
即根節點->左子樹->右子樹。
對任一子樹,先遍歷其左子樹,然后訪問根,最后遍歷其右子樹。
即左子樹->根節點->右子樹。
對任一子樹,先遍歷其左子樹,然后遍歷其右子樹,最后訪問根。
即左子樹->右子樹->根節點。
原則
①輸出根。
②訪問左子樹。【先訪問左子樹中的左子樹,再訪問左子樹中的右子樹。】直到訪問到葉子節點后輸出。
③訪問右子樹。【先訪問右子樹中的左子樹,再訪問右子樹中的右子樹。】直到訪問到葉子節點后輸出。
①訪問左子樹。【先訪問左子樹中的左子樹,再訪問左子樹中的右子樹。】直到訪問到葉子節點后輸出。
②輸出根。
③訪問右子樹。【先訪問右子樹中的左子樹,再訪問右子樹中的右子樹。】直到訪問到葉子節點后輸出。
①訪問左子樹。【先訪問左子樹中的左子樹,再訪問左子樹中的右子樹】。直到訪問到葉子節點后輸出。
②訪問右子樹。【先訪問右子樹中的左子樹,再訪問右子樹中的右子樹】。直到訪問到葉子節點后輸出。
③再返回訪問根,並輸出。
遍歷步驟

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用遞歸、非遞歸方式實現二叉樹的先序遍歷
View Code

 

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用遞歸、非遞歸方式實現二叉樹的中序遍歷
View Code

 

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用遞歸、非遞歸方式實現二叉樹的后序遍歷
View Code

 

三、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用遞歸、非遞歸方式實現二叉樹的層次遍歷
View Code

 

原文:https://www.cnblogs.com/sunshineliulu/p/7775214.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM