zoukankan      html  css  js  c++  java
  • 数据结构与算法之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);

    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>";

    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
    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);
  • 相关阅读:
    UVA 213 Message Decoding 【模拟】
    HDU 5976 Detachment 【贪心】 (2016ACM/ICPC亚洲区大连站)
    HDU 5979 Convex【计算几何】 (2016ACM/ICPC亚洲区大连站)
    HDU 5963 朋友 【博弈论】 (2016年中国大学生程序设计竞赛(合肥))
    HDU 5969 最大的位或 【贪心】 (2016年中国大学生程序设计竞赛(合肥))
    HDU 5968 异或密码 【模拟】 2016年中国大学生程序设计竞赛(合肥)
    HDU 5961 传递 【图论+拓扑】 (2016年中国大学生程序设计竞赛(合肥))
    HDU 5965 扫雷 【模拟】 (2016年中国大学生程序设计竞赛(合肥))
    HDU 5950 Recursive sequence 【递推+矩阵快速幂】 (2016ACM/ICPC亚洲区沈阳站)
    HDU 5952 Counting Cliques 【DFS+剪枝】 (2016ACM/ICPC亚洲区沈阳站)
  • 原文地址:https://www.cnblogs.com/sunshineliulu/p/7775214.html
Copyright © 2011-2022 走看看