目录
一、前言
接下来两天时间,我将详细整理二叉树的三种遍历方式---前序遍历、中序遍历、后序遍历。每种遍历方式我将主要从递归、迭代两种方式进行整理,之后我会单独整理Morris(莫里斯)算法遍历,感兴趣的朋友可以关注本专栏,我会尽快整理。
二、前序遍历
在前序遍历中,首先访问根节点,然后递归地对左子树进行前序遍历,最后递归地对右子树进行前序遍历。简单来说,前序遍历的遍历思想就是:根结点 ---> 左子树 ---> 右子树。
图一 前序遍历
如何在不编程的情况下快速计算二叉树的前序遍历呢?接下来我教给大家一个简单快捷的方法。
图二 小孔穿线法
这种快速计算方法我给起名为小孔穿线法,前序遍历的小孔穿线法就是在该二叉树的每个节点的左侧画一个小孔,然后依次连接起来,如图二所示,所以该二叉树的前序遍历结果为[1、2、4、5、3、6、7]。
当然该方法是为了让大家不通过编程来进行快速计算的,接下来我将从递归和迭代两种编程方法为大家讲解。(Morris算法本篇文章暂且先不讲,请关注后续)
三、递归
二叉树遍历,递归思想其实是最简单的方法。前序遍历我们递归的思想就是根结点 ---> 左子树 ---> 右子树。这个方法比较简单,我直接给伪代码了,不懂的同学可以私信或评论区问我。
struct TreeNode
{
int val;
struct TreeNode *left;
struct TreeNode *right;
};
void preorder(struct TreeNode* root, int* res, int *resSize)
{
if( !root )
{
return ;
}
res[(*resSize)++] = root->val;
preorder(root->left, res, resSize);
preorder(root->right, res, resSize);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize)
{
int* res = malloc(sizeof(int)*100);
*returnSize = 0;
preorder(root, res, returnSize);
return res;
}
时间复杂度:o(n)
空间复杂度:o(1)
四、迭代
递归的时候隐式地维护了一个栈,而我们在迭代的时候需要显式地将这个栈模拟出来,其余的实现与细节都相同,具体可以参考下面的代码。
struct TreeNode
{
int val;
struct TreeNode *left;
struct TreeNode *right;
};
int* preorderTraversal(struct TreeNode* root, int* returnSize)
{
int* res = malloc(sizeof(int)*100);
*returnSize = 0;
if( !root )
{
return res;
}
struct TreeNode* stack[100];
struct TreeNode* node = root;
int top = 0;
while( top > 0 || node != NULL )
{
while( node != NULL )
{
res[(*returnSize)++] = node->val;
stack[top++] = node;
node = node->left;
}
node = stack[--top];
node = node->right;
}
return res;
}
时间复杂度:o(n)
空间复杂度:o(1)
代码不懂的同学可以参考如下的图解:
图三
图四
图五
图六
图七
图八
图九
图十
图十一
图十二
图十三
图十四
图十五
图十六
图十七