今天学会了二叉树的三种遍历方式,根据自己的个人理解记录下来。
首先是最简单的递归法:
//先序
void ret1(struct TreeNode* root, int* returnSize,int* ans){
if(root==NULL)
return;
ans[(*returnSize)++]=root->val;
ret(root->left, returnSize,ans);
ret(root->right, returnSize,ans);
}
//中序
void ret2(struct TreeNode* root, int* returnSize,int* ans){
if(root==NULL)
return;
ret(root->left, returnSize,ans);
ans[(*returnSize)++]=root->val;
ret(root->right, returnSize,ans);
}
//后序
void ret3(struct TreeNode* root, int* returnSize,int* ans){
if(root==NULL)
return;
ret(root->left, returnSize,ans);
ret(root->right, returnSize,ans);
ans[(*returnSize)++]=root->val;
}
int* postorderTraversal(struct TreeNode* root, int* returnSize){
int* ans=(int*)malloc(sizeof(int)*100);
*returnSize=0;
ret1(root, returnSize,ans);
return ans;
}
递归的思路非常简单:调用自己+终止条件
迭代法:
迭代法的思路是通过模拟栈的方式达到递归调用的效果,但三种遍历方式的遍历操作大不相同。
先序:
0、初始设置:将根结点入栈
1、弹出栈顶结点,并将其数据输出
2、若此结点右节点不为空则入栈
3、若此结点左结点不为空则入栈
4、当栈空时退出循环
注意:这里需要先检查右结点,后检查左节点,以便弹出时先弹出左节点。
int* preorderTraversal(struct TreeNode* root, int* returnSize){
int* ans=(int*)malloc(sizeof(int)*100);
*returnSize=0;
struct TreeNode* stack[100];
if(root==NULL)
return ans;
int top=0;
stack[0]=root; //将根节点入栈
while(top!=-1){ //当栈不为空
struct TreeNode* node=stack[top--];//将栈顶结点弹出为当前结点
ans[(*returnSize)++]=node->val; //将当前结点数值输出(存入ans数组)
if(node->right!=NULL) //如果右子树不为空则入栈
stack[++top]=node->right;
if(node->left!=NULL) //如果左子树不为空则出栈
stack[++top]=node->left;
}
return ans;
}
后序:
0、将根节点入栈
1、弹出栈顶结点作为当前结点,并将数据输出
2、如果左节点不空则入栈
3、如果右节点不空则入栈
4、当栈空时退出循环
5、将答案数组翻转
注意:这里用了一个取巧的方法将先序的代码中左右结点入栈的顺序颠倒,先序的遍历顺序为头->左->右,颠倒后就变成了头->右->左。最后将答案数组颠倒变成左->右->头即可。
所以虽然最终的答案正确,但实际上并没有按照左->右->头的顺序遍历。
int* postorderTraversal(struct TreeNode* root, int* returnSize){
int* ans=(int*)malloc(sizeof(int)*100);
*returnSize=0;
if(root==NULL)
return ans;
struct TreeNode* stack[100];
int top=0;
stack[top]=root;//将根节点入栈
while(top!=-1){//当栈不为空时
struct TreeNode* node=stack[top--];//将栈顶结点弹出作为当前结点
ans[(*returnSize)++]=node->val;//将当前结点数据输出
if(node->left)//如果左节点不空则入栈
stack[++top]=node->left;
if(node->right)//如果右节点不空则入栈
stack[++top]=node->right;
}
int i=0,j=*returnSize-1;//将ans数组翻转
while(i<j){
int temp=ans[i];
ans[i++]=ans[j];
ans[j--]=temp;
}
return ans;
}
中序:
0、将根节点作为当前结点
1、if 当前结点不为空时入栈,当前结点继续向左走一步
2、else 弹出栈顶结点成为当前结点并输出,当前结点向右走一一步
3、栈空且当前结点为空时退出循环
int* inorderTraversal(struct TreeNode* root, int* returnSize){
int* ans=(int*)malloc(sizeof(int)*100);
*returnSize=0;
if(root==NULL)
return ans;
struct TreeNode* stack[100];
int top=-1;
struct TreeNode* node=root; //将根节点作为当前结点
while(top>-1||node!=NULL){ //当栈不为空或当前结点不为空时
if(node!=NULL){ //如果当前结点不为空则入栈
stack[++top]=node;
node=node->left; //当前结点继续向左
}
else{ //如果当前结点为空,说明向左走到头了
node=stack[top--];//弹出栈顶结点成为当前结点并输出
ans[(*returnSize)++]=node->val;
node=node->right;//当前结点继续向右
}
}
return ans;
}
中序遍历的大致思路为:先一直向左走到最左结点,然后向上返回一步,然后向右走一步,然后不断循环。
这就是我对于二叉树遍历的理解,如有错误欢迎指正。