二叉树的前中后序遍历(递归法和迭代法)

在上期的二叉树基础理论中提到了二叉树的前中后序遍历,这一期就简单的实现一下。下一期会实现一下层序遍历。

三种遍历的递归和迭代的相似和差别

三种遍历的递归法大差不差,可迭代法却有点差别。前序遍历和后序遍历的迭代法有点相似,可中序遍历的迭代法却不同于前两种。

迭代法其实就是借助栈来实现的,具体的注意事项和代码实现请接着看下面。

前序遍历

递归法

前序遍历的顺序的中左右。一般的递归会有三要素:1、确定递归函数的参数和返回值。2、确定终止条件。3、确定单层递归的逻辑。

以二叉树的前序遍历为例子:1、参数是数组,根结点,数组的长度(leetcode刷的多的读友们会很了解。)返回值是空,直接修改数组就好了,不需要返回值2、终止条件是结点为空。3、这里的单层逻辑就是中左右。

下面是C语言的代码实现

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
void preorder(struct TreeNode* root, int* arr, int* returnSize){
    if(!root){
        return;
    }
    arr[(*returnSize)++] = root->val;//中
    preorder(root->left, arr, returnSize);//左
    preorder(root->right, arr, returnSize);//右
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
    int* arr = (int*)malloc(sizeof(int) * 101);//这里的101是树的结点数。
    *returnSize = 0;
    preorder(root, arr, returnSize);
    return arr;
}

迭代法 

前序遍历的迭代法是借助栈来实现的。

栈的特性是先进后出,前序遍历是中左右,先将右结点放入栈中,再放入左结点。出来的顺序就是左-右。

/**
 * 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().
 */
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
    int* ret = (int*)malloc(sizeof(int) * 101);
    *returnSize = 0;
    if(!root){
        return ret;
    }
    struct TreeNode* stack[101];
//也可以struct TreeNode* stack = (struct TreeNode*)malloc(sizeof(struct TreeNode) * 101)
    int top = 0;
    stack[top++] = root;
    while(top){
        struct TreeNode* node = stack[--top];
        ret[(*returnSize)++] = node->val;
        if(node->right){
            stack[top++] = node->right;//右
        }
        if(node->left){
            stack[top++] = node->left;//左
        }
    }
    return ret;
}

 

中序遍历

递归法

和前序遍历类似,就是单层逻辑变成了左中右

/**
 * 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 inorder(struct TreeNode* root, int* arr, int* returnSize){
    if(!root){
        return;
    }
    inorder(root->left, arr, returnSize);//左
    arr[(*returnSize)++] = root->val;//中
    inorder(root->right, arr, returnSize);//右
}
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
    int* arr = (int*)malloc(sizeof(int) * 101);
    *returnSize = 0;
    inorder(root, arr, returnSize);
    return arr;
}

迭代法 

为什么说中序遍历的迭代和前后遍历不同呢,因为前后遍历的顺序都是中间结点在前,是需要先放入数组的结点。而中序是左右中,处理的结点和遍历的顺序不一致。也就是说,需要不断遍历树,直到最左边的叶子结点,然后再开始处理结点(也就是放入数组中)。所以就需要改变一下。

/**
 * 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().
 */
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
    int* ret = (int*)malloc(sizeof(int) * 101);
    *returnSize = 0;
    if(!root){
        return ret;
    }
    struct TreeNode* stack[101];
    int top = 0;
    struct TreeNode* node = root;
    while(node || top){
        if(node){
            stack[top++] = node;//这里就是不断先左将结点入栈,直到到达左叶子结点
            node = node->left;
        }
        else{
            node = stack[--top];//到了左叶子结点之后就开始弹栈
            ret[(*returnSize)++] = node->val;//弹出的结点就是需要处理的结点,将它存入数组中
            node = node->right;//然后再访问右结点。在将右结点入栈。(执行上面的选择语句)
        }
    }
    return ret;
}

后序遍历

递归法

/**
 * 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* arr, int* returnSize){
    if(!root){
        return;
    }
    postorder(root->left, arr, returnSize);//左
    postorder(root->right, arr, returnSize);//右
    arr[(*returnSize)++] = root->val;//中
}
int* postorderTraversal(struct TreeNode* root, int* returnSize) {
    int* arr = (int*)malloc(sizeof(int) * 200);
    *returnSize = 0;
    postorder(root, arr, returnSize);
    return arr;
}

迭代法

后序遍历的顺序是左右中,我们只需要将顺序变为中右左,然后倒序一下数组就ok了。

而前序的顺序是中左右,所以后序遍历的迭代和前序遍历非常像。只需要将左右结点入栈的顺序改变一下就行了。前序左右结点的入栈顺序是:右-左,所以后序就是:左-右。

/**
 * 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 Backarr(int* arr, int* returnSize){
    for(int i = 0, j = *returnSize - 1; i < j; i++, j--){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}
int* postorderTraversal(struct TreeNode* root, int* returnSize) {
    int* ret = (int*)malloc(sizeof(int) * 101);
    *returnSize = 0;
    if(!root){
        return ret;
    }
    struct TreeNode* stack[101];
    int top = 0;
    stack[top++] = root;
    while(top){
        struct TreeNode* node = stack[--top];
        ret[(*returnSize)++] = node->val;
        if(node->left){
            stack[top++] = node->left;//左
        }
        if(node->right){
            stack[top++] = node->right;//右
        }
    }
    Backarr(ret, returnSize);
    return ret;
}

总结

三种遍历的递归大差不差,但迭代却有区别,那么在下一期将会更新三种遍历的迭代统一格式。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值