1. 先序遍历
在先序遍历中,对节点的访问工作是在它的左右儿子被访问之前进行的。换言之,先序遍历访问节点的顺序是根节点-左儿子-右儿子。由于树可以通过递归来定义,所以树的常见操作用递归实现常常是方便清晰的。递归实现的代码如下:
void PreOrderTraversal(BinTree BT)
{
if( BT )
{
printf(“%d\n”, BT->Data); //对节点做些访问比如打印
PreOrderTraversal(BT->Left); //访问左儿子
PreOrderTraversal(BT->Right); //访问右儿子
}
}
由递归代码可以看出,该递归为尾递归(尾递归即递归形式在函数末尾或者说在函数即将返回前)。尾递归的递归调用需要用栈存储调用的信息,当数据规模较大时容易越出栈空间。虽然现在大部分的
编译器能够自动去除尾递归,但是即使如此,我们不妨自己去除。非递归先序遍历算法基本思路:使用
堆栈 a. 遇到一个节点,访问它,然后把它压栈,并去遍历它的左子树;
b. 当左子树遍历结束后,从栈顶弹出该节点并将其指向右儿子,继续a步骤;
c. 当所有节点访问完即最后访问的树节点为空且栈空时,停止。
实现代码如下:
void PreOrderTraversal(BinTree BT)
{
BinTree T = BT;
Stack S = CreatStack(MAX_SIZE); //创建并初始化堆栈S
while(T || !IsEmpty(S))
{
while(T) //一直向左并将沿途节点访问(打印)后压入堆栈
{
printf("%d\n", T->Data);
Push(S, T);
T = T->Left;
}
if (!IsEmpty(S))
{
T = Pop(S); //节点弹出堆栈
T = T->Right; //转向右子树
}
}
}
由以上例子可以看出,递归与非递归的本质区别就是递归是不断循环调用同一过程,非递归是循环执行同一个动作,并且非递归有入栈与出栈的过程,因此更节省存储空间。个人浅见,欢迎指正。