需求:
输入一个二叉树,采用非递归的方式,输出先序遍历的结果。
测试用例:
用以下层次遍历的序列代表二叉树
1234567#8####9#####
1234567########
73914#####5#6##
想法:
众所周知,二叉树的遍历用递归写起来就三行,但是当题目要求非递归的时候就比较难了。手动的模拟一下二叉树的先序遍历,其实可以发现用递归写出来的程序,实际执行的时候是按照回溯法的方式实现的。
而回溯法最好用栈实现,那么可以立即推非递归方法需要一个辅助栈,那么栈中元素都应该有什么呢?显然(想一想就知道了),栈中的每一个元素,除了树节点本身,还需要记录至少两个信息:当前节点的左子树是否访问完毕了,这里用has_get_left来表示,初始化是false,当左子树访问过以后就置位true;右子树依然。
基于这个有三个项的栈,非递归的算法就可以比较直观的表达出来(用文字写起来比较麻烦,但是我又不会用电脑画图,建议在纸上简单的把逻辑画一下):在一个循环的过程中,首先入栈,两个标志位都默认flase,当左子树不空且左子树可以访问的时候,把左子树入栈,然后继续下一次循环,否则右子树进行同样的操作,直到最后栈空。
这里值得一提的是,最开始的时候我是觉得直接用一个数组去模拟栈就好了,要不然还要写多写个pop、push两个函数怪麻烦的,然后实操起来发现用数组的话,在模拟入栈操作的时候还需要多写一部分清空脏数据的操作,实际上还不如最开始直接把最适合这个算法的栈写出来好用。
由此可见,对于一个具体问题,选择一个最适合的结构是很重要的。模拟的终究是模拟的,下次遇见这种问题我当然还是用一个数组(哈哈哈)。
源代码
struct node{
biTree* data;
bool left_has_get ;
bool right_has_get ;
bool this_has_get;
node* next;
};
void pre_travel_tree_norecursion(biTree* root)
{
if(root==NULL)
return;
node stack[20] ;
for(int i = 0; i <20;i++)
{
stack[i].left_has_get = false;
stack[i].right_has_get=false;
stack[i].this_has_get = false;
}
int top = 0;
stack[top].data = root; //用键值对的方式去思考
while(top>-1)
{
if(!stack[top].this_has_get)
{
printf("%d ",stack[top].data->data);
stack[top].this_has_get = true;
}
// ------------------------------------
//左子可访问,访问左子
if(stack[top] .data->leftSon != NULL && (!stack[top].left_has_get ))
{
stack[top].left_has_get = true;
stack[top+1].data = stack[top].data->leftSon;
stack[top+1].left_has_get=false;
stack[top+1].right_has_get=false;
stack[top+1].this_has_get =false;
top ++ ;
continue;
}
//右子可访问,访问右子
if(stack[top] .data->rightSon != NULL && (!stack[top].right_has_get ) )
{
stack[top].right_has_get = true;
stack[top+1].data = stack[top].data->rightSon;
stack[top+1].left_has_get=false;
stack[top+1].right_has_get=false;
stack[top+1].this_has_get =false;
top ++ ;
continue;
}
top -- ;
}
}