首先来写一下递归的!
对于递归要将大问题转化为小问题,并且要有一个结束的位置。
比如:要前序遍历一个二叉树,那就是先访问根节点,然后在访问根节点的左子树,在访问根节点的右子树,而左子树与右子树,又可以变成访问该节点和该结点的左子树和右子树。这就变成了一个递归的思想了。而终止条件就是:直到访问到叶子节点。
//递归
//前序遍历二叉树(根节点 左子树 右子树)
void BinaryTreePrevOrder(BTNode* root)
{
//终止条件
if (root == NULL)
{
return;
}
//先访问根节点,然后递归访问根节点的左子树和右子树
printf("%c ", root->_data);
BinaryTreePrevOrder(root->_left);
BinaryTreePrevOrder(root->_right);
}
//中序遍历二叉树(左子树 根节点 右子树)
void BinaryTreeInOrder(BTNode* root)
{
//终止条件
if (root == NULL)
{
return;
}
//先递归访问左子树,在访问根节点,在递归访问右子树
BinaryTreeInOrder(root->_left);
printf("%c ", root->_data);
BinaryTreeInOrder(root->_right);
}
//后序遍历二叉树(左子树 右子树 根节点)
void BinaryTreePostOrder(BTNode* root)
{
//终止条件
if (root == NULL)
{
return;
}
//先递归访问左子树。在递归访问右子树,最后访问根节点
BinaryTreePostOrder(root->_left);
BinaryTreePostOrder(root->_right);
printf("%c ", root->_data);
}
接下来再写一下非递归的。(使用栈)
对于非递归的二叉树的遍历。
//非递归遍历二叉树
//前序遍历(根节点 左子树 右子树)
//思路:先将该二叉树的左路结点压栈遍历完,然后在访问根节点,然后再对右结点进行刚才同样的事情,
//进行左路结点压栈遍历,然后在访问右结点,结束条件:该节点是叶子就不需要在进行压栈,对其进行出栈就可以了
void BinaryTreePrevOrderNonR(BTNode* root)
{
assert(root);
Stack s;
StackInit(&s);
BTNode* cur = root;
//StackEmpty必须存在因为在遍历的过程中,cur有可能会等于NULL
while (cur || StackEmpty(&s))
{
//将左路结点进行压栈
while (cur)
{
StackPush(&s, cur);
printf("%c ", cur->_data);
cur = cur->_left;
}
BTNode* top = StackTop(&s);
StackPop(&s);
cur = top->_right;
}
printf("\n");
}
//中序遍历(左子树 根节点 右子树)
//思想:中序遍历和前序遍历基本一样,只是在输出结点数据的位置不同,中序遍历是在对该节点进行出栈的时候,访问该节点
void BinaryTreeInOrderNonR(BTNode* root)
{
assert(root);
Stack s;
StackInit(&s);
BTNode* cur = root;
//StackEmpty必须存在因为在遍历的过程中,cur有可能会等于NULL
while (cur || StackEmpty(&s))
{
//将左路结点进行压栈
while (cur)
{
StackPush(&s, cur);
cur = cur->_left;
}
BTNode* top = StackTop(&s);
printf("%c ", top->_data);
StackPop(&s);
cur = top->_right;
}
printf("\n");
}
//后序遍历(左子树 右子树 根节点)
//思想:先将左路结点全部入栈,然后出栈的时候
//如何判断是否要访问该结点,
//如果该节点的右结点为空的话,或者该结点的右结点等于刚访问的上一个节点prev,那就直接访问该节点
//否则就是该节点的右结点没有进行访问呢,那就访问该节点的右结点
void BinaryTreePostOrderNonR(BTNode* root)
{
assert(root);
Stack s;
StackInit(&s);
//prev记录的是出栈的结点
BTNode* prev = NULL;
BTNode* cur = root;
//cur必须存在因为开始要从cur进入,只不过是在遍历的时候,cur绝对不会等于NULL
while (cur || StackEmpty(&s))
{
//将左路结点全部入栈
while (cur)
{
StackPush(&s, cur);
cur = cur->_left;
}
BTNode* top = StackTop(&s);
//说明该节点的右结点已经访问过了,可以进行输出了
if (top->_right == NULL || top->_right == prev)
{
StackPop(&s);
prev = top;
printf("%c ", top->_data);
}
//该节点的右结点没有访问过,那就继续对右结点进行子循环
else
{
cur = top->_right;
}
}
printf("\n");
}