二叉树递归遍历的体会

二叉树的递归遍历非常简单,其基本模型如下

前序遍历

前序遍历非常适用于由上往下进行访问的情景,比如求根节点到某一个结点沿途的权重和,那么用前序遍历是很好的。既可以带着一个变量进行遍历(利用引用或者外部变量),也可以通过设置返回值,然后最后进行综合,从而达到统一的结果。当然也可以在访问完,遍历完左右子树后,再根据结果来进行重新调整。(如第三个例子)

有时候为了记录上一个结点的信息对下一个结点的影响,我们会构造一个辅助函数,增加一个接口来提供信息,从而改变下一个结点,比如visit(Tree T,int x);

/*普通的前序遍历*/
void visit(TreeNode* T) {
}
void trans(TreeNode* root){
	visit(root);
	trans(root->left);
	trans(root->right);
}
/*带返回值的前序遍历,返回值会对结果产生效果*/
void visit(TreeNode* T) {
}
int trans(TreeNode* root){
	visit(root);
	int res1=trans(root->left);
	int res2=trans(root->right);
	return res1+res2;
}
/*例3*/
void visit(TreeNode* T) {
}
int trans(TreeNode* root){
	visit(root);
	int res1=trans(root->left);
	int res2=trans(root->right);
	visit2(root,res1,res2);//遍历完之后再重新调整
	return root->val;
}
中序遍历

中序遍历由于它的顺序的特殊性,在搜索树的遍历中,如果对它进行中序遍历,得到的就是一个从小到大的序列。而如果进行逆中序遍历,得到的就是一个从大到小的顺序。另外,我的体会是,中序遍历是一种左右分割式的遍历方式,就是如果当它访问一个点的时候,那么它的左边的所有结点都已经遍历完了(这看起来像废话,但是非常重要)
简单来说,中序遍历就是一种从左往右的遍历方式,将整棵树分成了左右两半。

void visit(TreeNode* T) {
}
void trans(TreeNode* root){
	trans(root->left);
	visit(root);
	trans(root->right);
}

在这里插入图片描述

后序遍历

后序遍历与前序遍历相反,它更多的是先遍历左右子树,然后再对当前结点进行处理。典型的应用比如将二叉树改造为所有的子树结点的和 这个时候,根结点的值必须要先确定了子结点的值,然后再确定根的值,这种逻辑是一层一层往上发展的。

void visit(TreeNode* T) {
}
void trans(TreeNode* root){
	trans(root->left);
	trans(root->right);
	visit(root);
}

另外补充一张leetcode上的图
在这里插入图片描述

非递归后序遍历

下面的代码来自于Knox
https://leetcode-cn.com/problems/binary-tree-postorder-traversal/solution/er-cha-shu-de-hou-xu-bian-li-by-leetcode/

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> ret;
        stack<TreeNode *> path;
        unordered_set<TreeNode *> _set; // 记录已经访问的结点

        if (root) path.push(root);

        while (!path.empty()) {
            auto node = path.top();

            bool leftVisited = true, rightVisited = true;

            // 左右结点判断先后顺序不能互换,因为需要先把右结点放进 stack中
            if (node->right && _set.find(node->right) == _set.end()) {
                rightVisited = false;
                path.push(node->right);
            }

            if (node->left && _set.find(node->left) == _set.end()) {
                leftVisited = false;
                path.push(node->left);
            }

            if (leftVisited && rightVisited) { // 左右结点已经访问过了,才可以访问当前结点
                ret.push_back(node->val);
                _set.insert(node);
                path.pop(); // 访问过了,从path中移除
            }
        }

        return ret;
    }
};
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值