版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hansionz/article/details/81910587
前言:二叉树的非递归遍历需要用到栈的一些操作,所以贴出栈的相关操作的链接
https://blog.csdn.net/hansionz/article/details/81636557
定义数据结构
typedef char BTDataType;
typedef struct BinaryTreeNode
{
BTDataType _data;
struct BinaryTreeNode* _left;
struct BinaryTreeNode* _right;
}BTNode;
1.前序遍历
递归:按照前序遍历的规则,先访问根节点,在递归遍历左子树,最后递归遍历右字树,整个问题可以转换成好多个子问题进行求解
void BinaryTreePrevOrder_R(BTNode* root)
{
//树为空,直接返回
if (root == NULL)
{
return;
}
//访问根
printf("%c", root->_data);
//递归访问左子树
BinaryTreePrevOrder_R(root->_left);
//递归访问右子树
BinaryTreePrevOrder_R(root->_right);
}
非递归:利用栈的后进先出性质
void BinaryTreePrevOrder(BTNode* root)
{
Stack s;
StackInit(&s);
BTNode* cur = root;
//cur不等于空说明左路还有结点没有访问,栈不为空说明还有右树未曾访问
while (cur || StackEmpty(&s) != 0)
{
//1.访问左路结点,并压栈
while (cur)
{
printf("%c", cur->_data);
StackPush(&s, cur);
cur = cur->_left;
}
//2.从栈里出来,说明左树已经被访问过了
BTNode* top = StackTop(&s);
StackPop(&s);
//3.子问题访问右树
cur = top->_right;
}
}
2.中序遍历
递归:按照中序遍历的规则,先递归遍历左子树,在访问根节点,最后递归遍历右字树,整个问题可以转换成好多个子问题进行求解
void BinaryTreeMidOrder_R(BTNode* root)
{
//树为空,直接返回
if (root == NULL)
{
return;
}
//递归访问左子树
BinaryTreeMidOrder_R(root->_left);
//访问根
printf("%c", root->_data);
//递归访问右子树
BinaryTreeMidOrder_R(root->_right);
}
非递归:利用栈的性质,先将左路结点全部压栈,出栈就说明栈顶元素左子树已经遍历完了,这时把栈顶元素的右子树当做是一个子问题来看待,遍历它的右子树,直到cur和栈都为空,则所有结点都被遍历完了
void BinaryTreeMidOrder(BTNode* root)
{
Stack s;
StackInit(&s);
BTNode* cur = root;
//cur不等于空说明左路还有结点没有压栈,栈不为空说明还有右树未曾访问
while (cur || StackEmpty(&s) != 0)
{
//1.先将左路结点压栈
while (cur)
{
StackPush(&s, cur);
cur = cur->_left;
}
//2.出栈说明左树已经访问完了,现在访问根节点
BTNode* top = StackTop(&s);
printf("%c", top->_data);
StackPop(&s);
//子问题访问右树
cur = top->_right;
}
}
3.后序遍历
递归:按照后序遍历的规则,先递归遍历左子树,在递归遍历右字树,最后在访问根节点,整个问题可以转换成好多个子问题进行求解
void BinaryTreePostOrder_R(BTNode* root)
{
//树为空,直接返回
if (root == NULL)
{
return;
}
//递归访问左子树
BinaryTreePostOrder_R(root->_left);
//递归访问右子树
BinaryTreePostOrder_R(root->_right);
//访问根
printf("%c", root->_data);
}
非递归:后序遍历的非递归相比前序、和中序的非递归比较难一些,因为后序遍历是先遍历左子树,在遍历右子树,最后访问根节点。当我们将左路的所有结点压栈,当要出栈遍历它的右子树的时候,我们并不知道右子树是否已经遍历过了,这点必须想个办法解决。
void BinaryTreePostOrder(BTNode* root)
{
Stack s;
StackInit(&s);
BTNode* cur = root;
BTNode* prev = NULL;
while (cur || StackEmpty(&s))
{
//1.将左路结点压栈
while (cur)
{
StackPush(&s, cur);
cur = cur->_left;
}
//2.取栈顶,出栈说明左路结点已经访问
BTNode* top = StackTop(&s);
//3.如果当前结点右树为空,则直接访问该节点;
// 如果右树存在,并且已经访问过,则直接访问它
//(prev是前一个被访问过的结点,如果右树的根节点等于prev,则说明右树被访问过)
if ((top->_right == NULL)||(prev == top->_right))
{
printf("%c", top->_data);
prev = top;
StackPop(&s);
}
//如果右树存在,并且没有访问过,则去访问它的右树(子问题)
else
{
cur = top->_right;
}
}
}
总结:二叉树的三中遍历,递归方法比较容易理解,但是非递归的方法是比较难理解的,建议以此篇博客学习的同学根据图和代码自己走上一遍,就可以更好的理解。