遍历二叉树的递归函数是体现了算法之美的高妙算法,思路清晰,代码简洁,读之赏心悦目。代码例如以下:
void PreOrderTraverse_R(BiTree BT) // 採用递归方式先序遍历二叉树BT
{
if(BT != NULL)
{
printf( " %c ", BT->data); // 输出该结点(根结点)
PreOrderTraverse_R(BT->lchild); // 遍历左子树
PreOrderTraverse_R(BT->rchild); // 遍历右子树
}
}
void InOrderTraverse_R(BiTree BT) // 採用递归方式中序遍历二叉树BT
{
if(BT != NULL)
{
InOrderTraverse_R(BT->lchild); // 遍历左子树
printf( " %c ", BT->data); // 输出该结点(根结点)
InOrderTraverse_R(BT->rchild); // 遍历右子树
}
}
void PostOrderTraverse_R(BiTree BT) // 採用递归方式后序遍历二叉树BT
{
if(BT != NULL)
{
PostOrderTraverse_R(BT->lchild); // 遍历左子树
PostOrderTraverse_R(BT->rchild); // 遍历右子树
printf( " %c ", BT->data); // 输出该结点(根结点)
}
}
相较之下,大部分流传的非递归遍历二叉树算法语言晦涩,面目可憎,尽管利用了栈数据结构来模拟递归遍历过程,但思路和表达形式上未能与递归算法相应起来,造成刚開始学习的人理解上的困惑。假设可以将非递归算法和递归算法相互相应,则可大慷慨便刚開始学习的人理解二者间的等效性。
我们知道,编译器在调用函数时会分配一个栈空间,以存储必要信息,假设该函数调用了别的函数,其栈空间会一直保留,直到该函数最后一条语句运行完成,才会释放其栈空间。在模拟非递归算法的时候,我们须要手工分配和释放栈空间。
三种不同的遍历方式差别在于栈空间的释放时机和输出结点信息时机的不同:先序和中序遍历是在訪问栈顶元素的右孩子(右子树)之前退栈,而后序遍历在訪问右子树之后退栈;先序遍历是在某结点入栈时输出其信息,而中序和后序遍历是在该结点退栈时输出其信息。
不管是递归算法还是非递归算法,都遵循上述规则,二者能够一一相应。图演示样例如以下:
附录:非递归算法代码例如以下:
void PreOrderTraverse_S(BiTree BT)//採用非递归方式先序遍历二叉树BT
{
BiTreep, stack[MAXSIZE];//p表示当前结点,栈stack[]用来存储结点
inttop = -1; //栈空
if(BT != NULL)//先推断是否为空树
{
p = BT;
while (p || top >= 0)
{
if (p != NULL) //先输出结点数据,再遍历左孩子
{
printf("%c",p->data);//输出该结点
stack[++top] = p;
p = p->lchild;
}
else
{
p = stack[top--]->rchild; //訪问栈顶元素右孩子,并退栈
}
}
}
}
void InOrderTraverse_S(BiTree BT)//採用非递归方式中序遍历二叉树BT
{
BiTreep, stack[MAXSIZE];//p表示当前结点,栈stack[]用来存储结点
inttop = -1; //栈空
if(BT != NULL)//先推断是否为空树
{
p = BT;
while (p || top >= 0)
{
if (p != NULL)//首先訪问左子树
{
stack[++top] = p;
p = p->lchild;
}
else
{
printf("%c",stack[top]->data);//输出栈顶元素
p = stack[top--]->rchild; //訪问栈顶元素右孩子,并退栈
}
}
}
}
void PostOrderTraverse_S(BiTree BT)//採用非递归方式后序遍历二叉树BT
{
BiTreep, stack[MAXSIZE];//p表示当前结点,栈stack[]用来存储结点
inttag[MAXSIZE] = {0}; //用来标志栈顶元素的右孩子是否被訪问过,0表示未訪问,1表示已訪问
inttop = -1; //栈空
if(BT != NULL)//先推断是否为空树
{
p = BT;
while (p || top >= 0)
{
if (p != NULL) //首先訪问左子树
{
stack[++top] = p;
tag[top] = 0;
p = p->lchild;
}
else if (tag[top] == 0) //若右子树尚未訪问,訪问栈顶元素右孩子,并做好标记
{
p= stack[top]->rchild;
tag[top]= 1;
}
else//否则输出栈顶元素并退栈
{
printf("%c",stack[top--]->data);
}
}
}
}