二叉树的遍历

199 阅读1分钟

前言:

  1. 树的前序遍历第一个节点=根节点,最后一个节点=右子树的最后一个节点
  2. 树的中序遍历第一个节点=左子树中序遍历的第一个节点,最后一个节点=右子树的中序最后一个节点
  3. 树的后续遍历第一个节点=左子树后续遍历的第一个节点,最后一个节点=根节点

递归实现

<?php
/*
* 二叉树节点定义
*/
class TreeNode {
    public $left = null;
    public $right = null;
    public $value = '';
    
    public function __construct($val) {
        $this->value = $val;
    }
}
/*
* 递归遍历二叉树
*/
class TreeRecursionScan{
    /*
     * 前序遍历二叉树
    */
    public function preOrder($root) {
        if (empty($root)) {
            return ;
        }
        // 遍历
        echo $root->value . PHP_EOL;
        $this->preOrder($root->left);
        $this->preOrder($root->right);
    }
    
    public function inOrder($root) {
        // todo
    }
    
    public function laOrder($root) {
        // todo
    }
}
?>

迭代实现

<?php
/*
* 二叉树节点定义
*/
class TreeNode {
    public $left = null;
    public $right = null;
    public $val = '';
    
    public function __construct($val) {
        $this->val = $val;
    }
}
/*
* 二叉树非递归遍历
*/
class TreeNoRecursionScan {
    /**
     * @desc 前序遍历
     * @param $root
     */
    public function preOrder($root) {
        // 利用栈,输出当前节点的值,然后将当前节点入栈
        // 如果当前节点没有左子树则弹出栈顶节点遍历其右子树
        $track = [];
        while (!empty($root) || !empty($track)) {
            while (!empty($root)) {
                echo $root->value . PHP_EOL;
                array_push($track, $root);
                $root = $root->left;
            }

            $root = array_pop($track)->right;
        }
    }
    
    // 中序遍历
    public function inOrder($root) {
        // 针对前序遍历改改输出节点值的时机
    }
    
    // 后续遍历
    public function laOrder($root) {
        // 与前序和中序不同的是后续遍历在遍历完成左子树之后
        // 不能直接从站中弹出节点,因为弹出后无法在遍历完成
        // 右子树之后读取当前节点的值
        
        // 使用一个变量存储遍历的上一个节点,表示当前节点的右子树是否已遍历
        $pre = null;
        $track = [];
        while (!empty($root) || !empty($track)) {
            while (!empty($root)) {
                array_push($track, $root);
                $root = $root->left;
            }

            $node = array_pop($track);
            // 该节点没有右子树
            // 右子树已经遍历完成
            if (empty($node->right) || $pre == $node->right) {
                echo $node->value . PHP_EOL;
                $pre = $node;
                $root = null;
            } else {
                array_push($track, $node->right);
                $root = $node->right;
            }
        }
    }
?>

算法分析

二叉搜索树的中序后续节点 leetcode

解法一 通用解法,中序遍历二叉搜索树,存储当前节点的前置节点,对比查找节点与前置节点如果一直则输出当前节点

class Solution {
    /**
     * @param TreeNode $root
     * @param TreeNode $p
     * @return TreeNode
     */
    function inorderSuccessor($root, $p) {
        $pre = null;
        $track = [];
        // 中序遍历
        $curr = $root;
        while (!empty($curr) || !empty($track)) {
            while (!empty($curr)) {
                $track[] = $curr;
                $curr = $curr->left;
            }
            
            $curr = array_pop($track);
            if ($pre->val == $p->val) {
                return $curr;
            }
            $pre = $curr;
            $curr = $curr->right;
        }

        return null;
    }
}

解法二 利用二叉搜索树的性质,通过对比当前节点的值与目标值的大小关系利用分治法遍历左子树和右子树

class Solution {
    /**
     * @param TreeNode $root
     * @param TreeNode $p
     * @return TreeNode
     */
    function inorderSuccessor($root, $p) {
        $track = [];
        $curr = $root;
        $pre = null;
        while (!empty($curr)) {
            // 当前节点小于等于目标值在右子树
            if ($p->val >= $curr->val) {
                $curr = $curr->right;
            } else {
               // 目标值若在左子树则中序后继是父节点
                $pre = $curr;
                $curr = $curr->left;
            }
        }

        return $pre;
    }
}