(笔记自用)Leetcode题目:二叉树的遍历(递归+迭代)

前序遍历——题目描述:

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

示例 1:

输入:root = [1,null,2,3]
输出:[1,2,3]

示例 2:

输入:root = []
输出:[]

示例 3:

输入:root = [1]
输出:[1]

示例 4:

输入:root = [1,2]
输出:[1,2]

示例 5:

输入:root = [1,null,2]
输出:[1,2]

提示:

  • 树中节点数目在范围 [0, 100] 内
  • -100 <= Node.val <= 100

解题方法:

1.递归法

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

//递归算法
//由于需要连续传参数组,故必须另写一个函数
void preOrder(struct TreeNode* node,int* returnSize,int* ans)
{
    if(node==NULL)
        return;
    else
        ans[(*returnSize)++]=node->val;
    preOrder(node->left,returnSize,ans);    
    preOrder(node->right,returnSize,ans);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize) 
{
    int* ans=(int*)malloc(sizeof(int)*101);
    *returnSize=0;  //returnSize必须赋值作为数组指针
    preOrder(root,returnSize,ans);
    return ans;
}

2.迭代法


//迭代算法
int* preorderTraversal(struct TreeNode* root, int* returnSize) 
{
    //定义返回数组
    int* ans=(int*)malloc(sizeof(int)*101);
    *returnSize=0;
    
    //定义栈结构
    struct TreeNode* stack[101];
    int top=0;

    while(top!=0 || root!=NULL) //注意此处是||而非&&
    {
        //将当前结点的所有左子树入栈
        while(root!=NULL)
        {
            ans[(*returnSize)++]=root->val;
            stack[top++]=root;
            root=root->left;
        }
        //出栈
        root=stack[--top];//由于上次++后top指向空,故此时应--
        //访问右孩子
        root=root->right;
    }
    return ans;
}

中序遍历——题目描述:

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

示例 1:

输入:root = [1,null,2,3]
输出:[1,3,2]

示例 2:

输入:root = []
输出:[]

示例 3:

输入:root = [1]
输出:[1]

提示:

  • 树中节点数目在范围 [0, 100] 内
  • -100 <= Node.val <= 100

解题思路:中序遍历与先序遍历的代码和解题思路十分相似,仅需要修改一下代码顺序,此处不过多赘述。

后序遍历——题目描述:

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 

示例 1:

输入:root = [1,null,2,3]
输出:[3,2,1]

示例 2:

输入:root = []
输出:[]

示例 3:

输入:root = [1]
输出:[1]

提示:

  • 树中节点的数目在范围 [0, 100] 内
  • -100 <= Node.val <= 100

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 

示例 1:

输入:root = [1,null,2,3]
输出:[3,2,1]

示例 2:

输入:root = []
输出:[]

示例 3:

输入:root = [1]
输出:[1]

提示:

  • 树中节点的数目在范围 [0, 100] 内
  • -100 <= Node.val <= 100

解题思路:

方法一:递归法:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

 //递归算法
void postOrder(struct TreeNode* root,int* ans,int* returnSize)
{
    if(!root)
        return;
    else
    {
        postOrder(root->left,ans,returnSize);
        postOrder(root->right,ans,returnSize);
        ans[(*returnSize)++]=root->val;
    }
}

int* postorderTraversal(struct TreeNode* root, int* returnSize) {
    int* ans=(int*)malloc(sizeof(int)*101);
    *returnSize=0;
    postOrder(root,ans,returnSize);
    return ans;
}

后序遍历的递归算法与先序和中序遍历的递归算法十分相似,区别仅在修改代码顺序。

方法二:迭代法:

// 迭代算法
//后序遍历
//定义一个TreeNode*变量prev,搜索到右节点时,
//把右节点赋给prev,之后出栈返回到根节点,如果根节点->==prev,那么说明右节点已经遍历过
int *postorderTraversal(struct TreeNode *root, int *returnSize)
{
    *returnSize = 0;
    int *res = (int *)malloc(sizeof(int) * 110);
    if (root == NULL)
        return res;
    struct TreeNode *cur = root;    //使用cur遍历当前节点
    struct TreeNode *stack[110];
    struct TreeNode *prev = NULL;   //使用prev记录已经遍历过的右节点
    int top = 0;
    while (cur || top > 0)
    {
        while (cur)     //将当前节点最左边的子树入栈
        {
            stack[top++] = cur;
            cur = cur->left;
        }
        cur = stack[--top];

        //迭代法后序遍历与先序\中序最大的不同
        if (cur->right == NULL || cur->right == prev)   //若 当前节点没有右子树 或 右子树已经访问过
        {
            res[(*returnSize)++] = cur->val;
            prev = cur;     //记录该节点以及被访问过,只要有节点入res,就将其更新未prev
            cur = NULL;
        }
        else    //否则访问右子树
        {
            stack[top++] = cur;
            cur = cur->right;
        }
    }
    return res;
}

非递归后序遍历,即迭代法,与先序和中序的迭代法解题思路不同。关键在于区分当前节点cur是否有右子树或节点的右子树是否已经被记录过(cur->right==prev),若没有右子树或右子树已经被访问,则使用prev记录该结点。这样,只要上一个记录过的结点都使用prev记录起来,这样就天然的完成了对已经记录的右子树标记。(由于后序遍历的特性:左→右→根,所以当前根若具有右子树,则一定是上一个被记录的节点)

  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值