问题:对二叉树的前序遍历(递归和非递归算法)
递归算法:输出根节点的值
对左子树进行左遍历
对右子树进行遍历
代码如下:
void PreorderTraversal(node *root)
{
if(root)
printf("%d\n",root->value);
else
return ;
PreorderTraversal(root->left);
PreorderTraversal(root->right);
}
这个算法的执行时间是多少呢?因为每个节点被检查了一次,所以它是O(n)级的。
非递归算法:要完成该算法,需要深入分析一下递归算法的本质,再用循环算法来模拟它的动作。递归算法使用了堆栈这种数据结构,利用堆栈来完成数据处理。
堆栈的四个函数:
int Push(element **stack,void *data);
int Pop(element **stact,void **data);
int CreateStack(element **stack);
int deleteStack(element **stack);
首先来探究下递归算法的本质:
递归算法:a.输出根节点的值
b.对左子树进行左遍历
c.对右子树进行遍历
第一次进入递归函数的时候,先输出根节点的值,然后递归地调用这个函数对左子树进行遍历。在发出这个递归调用的时候,调用者的程序状态就会被压入堆栈保存起来,这样在递归调用返回时,调用者就能从自己离开的地方开始继续执行。
对左遍历算法来说,调用者将继续对右子树进行左遍历。为了能在遍历完左子树之后开始对右子树的遍历,递归调用隐含地把右子树的地址保存在堆栈上。在输出一个节点之后但在前进到它的左节点之前,该节点的右节点将被压入一个你不知道的堆栈里保存起来。当没有子节点可供处理时,就会从递归调用中返回一层,从堆栈上弹出一个右节点,然后以它为起点继续进行左遍历。
总结:这个算法先输出当前节点的值,然后再把它的右节点压入堆栈,然后前进到它的左节点;当没有子节点可供处理时,算法将从堆栈上弹出一个新的当前节点。这个过程将一直重复到遍历完所有的节点为止,堆栈里也不再有任何数据。
注:必须保证左节点总是先于右节点被弹出来,所以得先压入右节点,再压入左节点。
非递归算法如下:
创建堆栈
把根节点压入堆栈
当堆栈不为空,循环
弹出一个节点
如果这个节点不是NULL
输出它的值
把这个节点的右节点压入堆栈
把这个节点的左节点压入堆栈
代码如下:
void PreorderTraversal(node *root)
{
element *theStack;
void *data;
node *curNode;
CreateStack(&theStack);
Push(&theStack,root);
while(Pop(&theStack,&data))
{
curNode=(node *)data;
if(curNode)
{
printf("%d\n",curNode->value);
Push(&theStack,curNode->right);
Push(&theStack,curNode->left);
}
}
DeleteStack(&theStack);
}
这个算法的时间开销也是O(n)