二叉树的遍历(递归和非递归的方法)

 

一.使用递归的方法进行二叉树的遍历

二叉树是一种非常重要的数据结构,很多其他数据机构都是基于二叉树的基础演变过来的。二叉树有前、中、后三种遍历方式,因为树的本身就是用递归定义的,因此采用递归的方法实现三种遍历,不仅代码简洁且容易理解,但其开销也比较大,而若采用非递归方法实现三种遍历,则要用栈来模拟实现(递归也是用栈实现的)。

三种遍历方式的递归实现

1、先序遍历——按照“根节点-左孩子-右孩子”的顺序进行访问。

1.void pre_traverse(BTree pTree)  
2.{  
3.    if(pTree)  
4.    {  
5.        printf(”%c ”,pTree->data);  
6.        if(pTree->pLchild)  
7.            pre_traverse(pTree->pLchild);  
8.        if(pTree->pRchild)  
9.            pre_traverse(pTree->pRchild);      
10.    }  
11.}  

    2、中序遍历——按照“左孩子-根节点-右孩子”的顺序进行访问。

1.void in_traverse(BTree pTree)  
2.{  
3.    if(pTree)  
4.    {  
5.        if(pTree->pLchild)  
6.            in_traverse(pTree->pLchild);  
7.        printf(”%c ”,pTree->data);  
8.        if(pTree->pRchild)  
9.            in_traverse(pTree->pRchild);   
10.    }  
11.}  

3、后序遍历——按照“左孩子-右孩子-根节点”的顺序进行访问。

1.void beh_traverse(BTree pTree)  
2.{  
3.    if(pTree)  
4.    {  
5.        if(pTree->pLchild)  
6.            beh_traverse(pTree->pLchild);  
7.        if(pTree->pRchild)  
8.            beh_traverse(pTree->pRchild);      
9.        printf(”%c ”,pTree->data);  
10.}  

二.非递归进行二叉树遍历(可以借助栈实现二叉树的递归遍历转换为非递归遍历)

先序遍历算法基本思路:使用堆栈

a. 遇到一个节点,访问它,然后把它压栈,并去遍历它的左子树;

b. 当左子树遍历结束后,从栈顶弹出该节点并将其指向右儿子,继续a步骤;

c. 当所有节点访问完即最后访问的树节点为空且栈空时,停止。

typedef struct TreeNode *PtrToNode;
typedef struct TreeNode *BinTree;

struct TreeNode
{
    int Data;    //为简单起见,不妨假设树节点的元素为int型
    BinTree Left;
    BinTree Right;
};
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;  //转向右子树
        }
    }
}

中序遍历非递归辅助栈实现

void InOrderTraversal(BinTree BT)
{ 
    BinTree T = BT;
    Stack S = CreatStack(MaxSize); //创建并初始化堆栈S
    while(T || !IsEmpty(S))
  {
      while(T)    //一直向左并将沿途节点压入堆栈
      { 
          Push(S,T);
          T = T->Left;
      }
      if(!IsEmpty(S))
      {
          T = Pop(S);                //节点弹出堆栈
          printf("%d\n", T->Data);    //(访问) 打印结点
          T = T->Right;              //转向右子树
      }
  }
}

序遍历非递归辅助栈实现

思想:因为后序非递归遍历二叉树的顺序是先访问左子树,再访问右子树,最后访问根节点。当用栈来存储结点,必须分清返回根节点时,是从左子树返回,还是从右子树返回。使用辅助指针r,指向最近访问过的结点。也可以在结点中增加一个标志域,记录是否已被访问。

struct BiTreeNode
{
	int data;
	BiTreeNode* lchild;
	BiTreeNode* rchild;
};

void PostOrder(BiTreeNode* T)
{
	stack<BiTreeNode*> s;
	BiTreeNode*p = T, *r = NULL, temp;
	while (p || !s.empty())
	{
		if (p)
		{
			s.push(p);
			p = p->lchild;
		}
		else
		{
			p = s.top();
			if (p->rchild&&p->rchild != r)
			{
				p = p->rchild;
				s.push(p);
				p = p->lchild;
			}
			else
			{
				p = s.top();
				s.pop();
				cout << p->data;
				r = p;
				p = NULL;
			}

		}//else
	}//while
}

层序遍历(实现用到队列,自顶相下,自左向右)

  二叉树遍历的核心问题是二维结构的线性化。我们通过节点访问其左右儿子时,存在的问题是访问左儿子后,右儿子怎么访问。因此我们需要一个存储结构保存暂时不访问的节点。前面三种遍历方式的非递归实现,我们是通过堆栈来保存。事实上也可以通过队列来保存。

  队列实现的基本思路:遍历从根节点开始,首先将根节点入队,然后执行循环:节点出队,访问(访问)根节点,将左儿子入队,将右儿子入队,直到队列为空停止。

  这种遍历方式的结果是将二叉树从上到下,从左至右一层一层的遍历,即层序遍历,代码实现如下:

void LevelOrderTraversal(BinTree BT)
{
    BinTree T;
    Queue Q;    //声明一个队列
    if (BT == NULL)
        return;                 //如果树为空,直接返回
    Q = CreatQueue(MAX_SIZE);   //创建并初始化队列
    AddQ(Q, BT);                //将根节点入队
    while (!IsEmpty(Q))
    {
        T = DeleteQ(Q);              //节点出队
        printf("%d\n", T->Data);         //访问出队的节点
        if (T->Left)    AddQ(Q, T->Left);   //若左儿子不为空,将其入队 
        if (T->Right)    AddQ(Q, T->Right)  //若右儿子不为空,将其入队    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值