二叉树的遍历:前序,中序,后序,层序--包括递归和非递归实现

/**//********************************************************************
    created:    2005/12/30
    created:    30:12:2005   10:39
    filename:     bintree.h
    author:        Liu Qi
    
    purpose:    二叉树的3种遍历方式(包括非递归实现),前序,后序和中序,先访问根节点就是
    前序(部分书籍称为先根遍历,个人觉得该说法更好^_^),类似的,最后访问根节点就是后序
********************************************************************
*/



#ifndef TREE_H
#define TREE_H


#include <stdio.h>
#include <malloc.h>
#include <stack>
#include <queue>
#include <assert.h>

using namespace std;



typedef int ElemType;

typedef struct treeT
{
    ElemType key;
    struct treeT* left;
    struct treeT* right;
}
treeT, *pTreeT;




/**//*===========================================================================
* Function name:    visit
* Parameter:        root:树根节点指针
* Precondition:        
* Description:        
* Return value:        
* Author:            Liu Qi, //-
===========================================================================
*/

static void visit(pTreeT root)
{
    if (NULL != root)
    {
        printf(" %d\n", root->key);
    }

}




/**//*===========================================================================
* Function name:  BT_MakeNode    
* Parameter:      target:元素值    
* Precondition:      None    
* Postcondition:  NULL != pTreeT 
* Description:      构造一个tree节点,置左右指针为空,并且返回指向新节点的指针    
* Return value:      指向新节点的指针    
* Author:            Liu Qi,  [12/30/2005]
===========================================================================
*/

static pTreeT BT_MakeNode(ElemType target)
{
    pTreeT pNode = (pTreeT) malloc(sizeof(treeT));

    assert( NULL != pNode ); 

    pNode->key   = target;
    pNode->left  = NULL;
    pNode->right = NULL;
    
    return pNode;
}



/**//*===========================================================================
* Function name:    BT_Insert
* Parameter:        target:要插入的元素值, pNode:指向某一个节点的指针
* Precondition:         NULL != ppTree 
* Description:        插入target到pNode的后面
* Return value:        指向新节点的指针
* Author:            Liu Qi,  [12/29/2005]
===========================================================================
*/

pTreeT BT_Insert(ElemType target, pTreeT* ppTree)
{
    pTreeT Node;

    assert( NULL != ppTree ); 

    Node = *ppTree;
    if (NULL == Node)
    {
        return *ppTree = BT_MakeNode(target);
    }


    if (Node->key == target)    //不允许出现相同的元素
    {
        return NULL;
    }

    else if (Node->key > target)    //向左
    {
        return BT_Insert(target, &Node->left);
    }

    else
    {
        return BT_Insert(target, &Node->right);
    }

}





/**//*===========================================================================
* Function name:    BT_PreOrder
* Parameter:        root:树根节点指针
* Precondition:        None
* Description:        前序遍历
* Return value:        void
* Author:            Liu Qi,  [12/29/2005]
===========================================================================
*/

void BT_PreOrder(pTreeT root)
{
    if (NULL != root)
    {
        visit(root);
        BT_PreOrder(root->left);
        BT_PreOrder(root->right);
    }
    
}



/**//*===========================================================================
* Function name:    BT_PreOrderNoRec
* Parameter:        root:树根节点指针
* Precondition:        Node
* Description:        前序(先根)遍历非递归算法
* Return value:        void
* Author:            Liu Qi,  [1/1/2006]
===========================================================================
*/

void BT_PreOrderNoRec(pTreeT root)
{
    stack<treeT *> s;

    while ((NULL != root) || !s.empty())
    {
        if (NULL != root)
        {
            visit(root);
            s.push(root);
            root = root->left;
        }

        else
        {
            root = s.top();
            s.pop();
            root = root->right;
        }

    }

}




/**//*===========================================================================
* Function name:    BT_InOrder
* Parameter:        root:树根节点指针
* Precondition:        None
* Description:        中序遍历
* Return value:        void
* Author:            Liu Qi,  [12/30/2005]
===========================================================================
*/

void BT_InOrder(pTreeT root)
{
    if (NULL != root)
    {
        BT_InOrder(root->left);
        visit(root);
        BT_InOrder(root->right);
    }

}



/**//*===========================================================================
* Function name:    BT_InOrderNoRec
* Parameter:        root:树根节点指针
* Precondition:        None
* Description:        中序遍历,非递归算法
* Return value:        void
* Author:            Liu Qi,  [1/1/2006]
===========================================================================
*/

void BT_InOrderNoRec(pTreeT root)
{
    stack<treeT *> s;
    while ((NULL != root) || !s.empty())
    {
        if (NULL != root)
        {
            s.push(root);
            root = root->left;
        }

        else
        {
            root = s.top();
            visit(root);
            s.pop();
            root = root->right;
        }

    }

}




/**//*===========================================================================
* Function name:    BT_PostOrder
* Parameter:        root:树根节点指针
* Precondition:        None
* Description:        后序遍历
* Return value:        void
* Author:            Liu Qi,  [12/30/2005]
===========================================================================
*/

void BT_PostOrder(pTreeT root)
{
    if (NULL != root)
    {
        BT_PostOrder(root->left);
        BT_PostOrder(root->right);
        visit(root);    
    }

}



/**//*===========================================================================
* Function name:    BT_PostOrderNoRec
* Parameter:        root:树根节点指针
* Precondition:        None
* Description:        后序遍历,非递归算法
* Return value:        void
* Author:            Liu Qi, //  [1/1/2006]
===========================================================================
*/

void BT_PostOrderNoRec(pTreeT root)
{
前序、中序、后序的非递归遍历中,要数后序最为麻烦,如果只在栈中保留指向结点的指针,那是不够的,必须有一些额外的信息存放在栈中。
方法有很多,这里只举一种,先定义栈结点的数据结构
typedef struct{Node * p; int rvisited;}SNode //Node 是二叉树的结点结构,rvisited==1代表p所指向的结点的右结点已被访问过。


lastOrderTraverse(BiTree bt){
  //首先,从根节点开始,往左下方走,一直走到头,将路径上的每一个结点入栈。
  p = bt;
  while(bt){
    push(bt, 0); //push到栈中两个信息,一是结点指针,一是其右结点是否被访问过
    bt = bt.lchild;
  }


  //然后进入循环体
  while(!Stack.empty()){ //只要栈非空
    sn = Stack.getTop(); // sn是栈顶结点


    //注意,任意一个结点N,只要他有左孩子,则在N入栈之后,N的左孩子必然也跟着入栈了(这个体现在算法的后半部分),所以当我们拿到栈顶元素的时候,可以确信这个元素要么没有左孩子,要么其左孩子已经被访问过,所以此时我们就不关心它的左孩子了,我们只关心其右孩子。


    //若其右孩子已经被访问过,或是该元素没有右孩子,则由后序遍历的定义,此时可以visit这个结点了。
    if(!sn.p.rchild || sn.rvisited){
      p = pop();
      visit(p);
    }
    else //若它的右孩子存在且rvisited为0,说明以前还没有动过它的右孩子,于是就去处理一下其右孩子。
    { 
      //此时我们要从其右孩子结点开始一直往左下方走,直至走到尽头,将这条路径上的所有结点都入栈。


      //当然,入栈之前要先将该结点的rvisited设成1,因为其右孩子的入栈意味着它的右孩子必将先于它被访问(这很好理解,因为我们总是从栈顶取出元素来进行visit)。由此可知,下一次该元素再处于栈顶时,其右孩子必然已被visit过了,所以此处可以将rvisited设置为1。
      sn.rvisited = 1;


      //往左下方走到尽头,将路径上所有元素入栈
      p = sn.p.rchild;
      while(p != 0){
        push(p, 0);
        p = p.lchild;
      }
    }//这一轮循环已结束,刚刚入栈的那些结点我们不必管它了,下一轮循环会将这些结点照顾的很好。
  }
}
}



/**//*===========================================================================
* Function name:    BT_LevelOrder
* Parameter:        root:树根节点指针
* Precondition:        NULL != root
* Description:        层序遍历
* Return value:        void
* Author:            Liu Qi,  [1/1/2006]
===========================================================================
*/

void BT_LevelOrder(pTreeT root)
{
    queue<treeT *> q;
    treeT *treePtr;

    assert( NULL != root ); 

    q.push(root);

    while (!q.empty())
    {
        treePtr = q.front();
        q.pop();
        visit(treePtr);

        if (NULL != treePtr->left)
        {
            q.push(treePtr->left);    
        }

        if (NULL != treePtr->right)
        {
            q.push(treePtr->right);
        }
    
            
    }

}



#endif



测试代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "tree.h"

#define MAX_CNT 5
#define BASE  100

int main(int argc, char *argv[])
{
    int i;
    pTreeT root = NULL;
    
    srand( (unsigned)time( NULL ) ); 
    
    for (i=0; i<MAX_CNT; i++)
    {
        BT_Insert(rand() % BASE, &root);
    }


    //前序
    printf("PreOrder:\n");
    BT_PreOrder(root);
    printf("\n");

    printf("PreOrder no recursion:\n");
    BT_PreOrderNoRec(root);
    printf("\n");
    
    //中序
    printf("InOrder:\n");
    BT_InOrder(root);
    printf("\n");

    printf("InOrder no recursion:\n");
    BT_InOrderNoRec(root);
    printf("\n");

    //后序
    printf("PostOrder:\n");
    BT_PostOrder(root);
    printf("\n");

    //层序
    printf("LevelOrder:\n");
    BT_LevelOrder(root);
    printf("\n");
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值