【算法题】二叉树的前序遍历(递归和非递归算法分析)

          问题:对二叉树的前序遍历(递归和非递归算法)

递归算法输出根节点的值
         对左子树进行左遍历
         对右子树进行遍历

 
代码如下:

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)

    原文作者:递归算法
    原文地址: https://blog.csdn.net/xiaoding133/article/details/8031425
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞