为了加深对二叉树遍历思想的理解,以及锻炼分析和解决问题的能力,以下对前序遍历二叉树的非递归实现算法进行分析、实现及总结。
分析:给定任意一棵二叉树,对其进行前序遍历,即先访问根结点,然后访问左其孩子,再访问其右孩子。但是用二叉链实现的二叉树其结点的本质是具有两个指针域的单向链表的结点,既然是单链表结点,就意味着直接向前访问了某个结点后,将无法访问这个结点的兄弟结点,因此需要考虑将要访问某个孩子结点或者正在访问某个结点时,寄存这个结点的双亲结点或者寄存这个结点的兄弟结点。
另外,根据二叉树的前序遍历思想,靠近根结点的右孩子结点会保留到后面访问,而远离根结点的右孩子结点会先被访问,即对右孩子结点的访问满足“后进先出”——栈的思想
(鉴于本人能力有限,文字描述不能完全表达此算法的思想,以上只是分析主要的两点思想)
因此,可以尝试的方法有二:
- 用栈寄存被访问的结点(间接寄存:寄存双亲结点,以便后续找到其右孩子结点)
- 用栈寄存被访问结点的兄弟结点(直接寄存右孩子结点)
法一:栈寄存双亲结点
/*算法抽象为两个步:
* 循环执行这两步,直到遍历完整棵树
* 1. 从根结点开始“一竿子到底”向左边访问边入栈,直到结点为NULL
* 2. 遇到结点为NULL以后,出栈结点并获取右孩子结点,重复上一步,
* 直到栈为空并且当前结点为NULL
*/
void PreTravel1(BTNode *btree_p)
{
BTNode *node_p = btree_p;
SqStack *stack_p;
InitStack(stack_p);
while (!StackEmpty(stack_p) || node_p != NULL)
{
while (node_p != NULL)
{
printf("%c", node_p->data);
Push(stack_p, node_p);
node_p = node_p->lchild;
}
if (!StackEmpty(stack_p))
{
Pop(stack_p, node_p);
node_p = node_p->rchild;
}
}
printf("\n");
DestroyStack(stack_p);
}
法二:栈寄存兄弟结点
/*算法抽象为一步:
* 循环执行这一步,直到遍历完整棵树
* 1. 出栈一个结点,进行访问;若右孩子结点非NULL,入栈;若左孩子结点非* NULL,入栈;
*/
void PreTravel2(BTNode *btree_p)
{
BTNode *node_p;
SqStack *stack_p;
InitStack(stack_p);
if (btree_p != NULL)
{ node_p = btree_p;
Push(stack_p, node_p);
while (!StackEmpty(stack_p))
{
Pop(stack_p, node_p);
printf("%c", node_p->data);
if (node_p->rchild != NULL)
Push(stack_p, node_p->rchild);
if (node_p->lchild != NULL)
Push(stack_p, node_p->lchild);
}
}
printf("\n");
DestroyStack(stack_p);
}
以上