leetcode【数据结构简介】《二叉树》卡片——树的遍历

Authur Whywait 做一块努力吸收知识的海绵
想看博主的其他所有leetcode卡片学习笔记链接?传送门点这儿

关于树和二叉树的介绍

是一种经常用到的数据结构,用来模拟具有树状结构性质的数据集合。

树里的每一个节点有一个根植和一个包含所有子节点的列表。从图的观点来看,树也可视为一个拥有N 个节点N-1 条边的一个有向无环图。

二叉树是一种更为典型的树树状结构。如它名字所描述的那样,二叉树是每个节点最多有两个子树的树结构,通常子树被称作“左子树”和“右子树”。

树的遍历 - 介绍

前序遍历 - 前序遍历首先访问根节点,然后遍历左子树,最后遍历右子树。
中序遍历 - 中序遍历是先遍历左子树,然后访问根节点,然后遍历右子树。
后序遍历 - 后序遍历是先遍历左子树,然后遍历右子树,最后访问树的根节点。

通常来说,对于二叉搜索树,我们可以通过中序遍历得到一个递增的有序序列。 我们将在另一张卡片(数据结构介绍 – 二叉搜索树)中再次提及。

值得注意的是,当你删除树中的节点时,删除过程将按照后序遍历的顺序进行。 也就是说,当你删除一个节点时,你将首先删除它的左节点和它的右边的节点,然后再删除节点本身。

后序在数学表达中被广泛使用。 编写程序来解析后缀表示法更为容易…

二叉树的前序遍历 - 练习

给定一个二叉树,返回它的 前序 遍历.

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

递归算法

/**
 * 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* root, int* array, int* returnSize){
    if(!root) return;
    array[(*returnSize)++] = root->val;
    preorder(root->left, array, returnSize);
    preorder(root->right, array, returnSize);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize){
    * returnSize = 0;
    if(!root) return NULL;
    int* array = (int *)malloc(sizeof(int) * 100000);
    preorder(root, array, returnSize);
    return array;
}

在这里插入图片描述

二叉树的中序遍历 - 练习

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

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

递归算法

void inorder(struct TreeNode* root, int* array, int* returnSize){
    if(!root) return;
    inorder(root->left, array, returnSize);
    array[(*returnSize)++] = root->val;
    inorder(root->right, array, returnSize);
}

int* inorderTraversal(struct TreeNode* root, int* returnSize){
    * returnSize = 0;
    if(!root) return NULL;
    int* array = (int *)malloc(sizeof(int) * 100000);
    inorder(root, array, returnSize);
    return array;
}

在这里插入图片描述

二叉树的后序遍历 - 练习

给定一个二叉树,返回它的 后序 遍历。

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

递归算法

void postorder(struct TreeNode* root, int* array, int* returnSize){
    if(!root) return;
    postorder(root->left, array, returnSize);
    postorder(root->right, array, returnSize);
    array[(*returnSize)++] = root->val;
}
int* postorderTraversal(struct TreeNode* root, int* returnSize){
    * returnSize = 0;
    if(!root) return NULL;
    int* array = (int *)malloc(sizeof(int) * 100000);
    postorder(root, array, returnSize);
    return array;
}

在这里插入图片描述

前序中序后序 - 比较

比较上面三种遍历的递归方法,我们可以发现:

在程序实现的时候,不同遍历方式的唯一区别就在函数里三条语句的顺序而已。

postorder(root->left, array, returnSize);
postorder(root->right, array, returnSize);
array[(*returnSize)++] = root->val;

也就是根、左子树和右子树三者谁先将其的val写入数组array中。

记忆小技巧

左子树总是先比右子树遍历,“前中后”指的是根结点的位置。

解释:
左子树总是比右子树先入数组;
如果根节点在比左子树先入数组array,则为前序;
如果根节点在左右子树之间入数组array,则为中序;
如果根节点在比右子树先入数组array,则为后序;

【注】"入数组array"这种表达方式显得更直观一些,而array是我们最后要返回的数组,数组里元素的顺序就是遍历的顺序。

层序遍历

层序遍历就是逐层遍历树结构。

广度优先搜索 (BFS算法)是一种广泛运用在树或图这类数据结构中,遍历或搜索的算法。 该算法从一个根节点开始,首先访问节点本身。 然后遍历它的相邻节点,其次遍历它的二级邻节点、三级邻节点,以此类推。

当我们在树中进行广度优先搜索时,我们访问的节点的顺序是按照层序遍历顺序的。

队列以及BFS相关传送门点这儿

二叉树的层序遍历 - 练习

给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。

二叉树:[3,9,20,null,null,15,7],
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]

BFS算法

代码用的是之前在队列和栈卡片中(点这里是传送门)中提到的模板,也没有用什么循环队列,只是把空间开得足够大罢了,这样的作法是省时间。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
# define MAXSIZE 10000
int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes){
    * returnSize=0;
    if(!root) return NULL;
    int **array = (int **)malloc(sizeof(int*) * MAXSIZE);

    struct TreeNode Root = *root;
    struct TreeNode* queue = (struct TreeNode *)malloc(sizeof(struct TreeNode) * MAXSIZE);
    int front=0, tail=0;
    * returnColumnSizes = (int *)malloc(sizeof(int) * MAXSIZE);

    array[* returnSize] = (int *)malloc(sizeof(int));
    array[* returnSize][0] = root->val;
    (* returnColumnSizes)[* returnSize] = 1;
    queue[tail++] = *root;
    
    while(front<tail){
        (* returnSize)++;
        int counter=0;
        int size=tail-front;
        array[* returnSize] = (int *)malloc(sizeof(int) * MAXSIZE);
        for(int i=0; i<size; i++){
            if(!queue[front].left && !queue[front].right){
                front++; 
                continue;
            }
            if(queue[front].left){
                queue[tail++] = *(queue[front].left);
                array[* returnSize][counter++] = queue[front].left->val;
            }
            if(queue[front].right){
                queue[tail++] = *(queue[front].right);
                array[* returnSize][counter++] = (*(queue[front].right)).val;
            }
            front++;
        }
        (* returnColumnSizes)[* returnSize] = counter;
    }
    return array;
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200402183051962.png)

>都看到了这里,不点个👍再走?(╯‵□′)╯︵┻━┻
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AuthurLEE

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值