二叉树的遍历

遍历的概念:
“遍历”: 沿某条搜索路径巡访二叉树的结点, 使每个结点均被访问一次, 且仅被访问一次。

用L、D、R表示遍历左子树、访问根结点、遍历右子树,
先左后右的遍历算法:(命名即根据访问根结点的先后次序)
先序遍历:DLR
中序遍历:LDR
后序遍历:LRD

先序遍历思路:
- 若为空树,则空操作
1. 访问根结点
2. 先序遍历左子树
3. 先序遍历右子树

中序遍历思路:
- 若为空树,则空操作
1. 先序遍历左子树
2. 访问根结点
3. 先序遍历右子树

后序遍历思路:
- 若为空树,则空操作
1. 先序遍历左子树
2. 先序遍历右子树
3. 访问根结点

按层次遍历思路:(借助队列先进先出的特性)
1. 初始化队列(置队空)
2. 将树的根指针入队(队列存储类型为树的结点的指针类型)
3. 循环(当满足“队列非空”时执行下面操作)
- 取出队头元素(即队头位置存的结点指针)
- 打印队头元素所指结点的key值
- 若该队头元素所指结点的左孩子非空,入队
- 若该队头元素所指结点的右孩子非空,入队

数据存储结构:

typedef struct BiTree{
    ElemType key;//结点值
    struct BiTree *left;//左孩子
    struct BiTree *right;//右孩子
    struct BiTree *p;//双亲
}BiTNode,*BiTree;
代码实现

1.先序遍历

void PreOrder(BiTree bt)
{
    if(bt!=NULL)//根指针为bt
    {
        printf("%d",bt->key);//访问根结点
        PreOrder(bt->left);//遍历左子树
        PreOrder(bt->right);//遍历右子树
    }
}

2.中序遍历

void InOrder(BiTree bt)
{
    if(bt!=NULL)//根指针为bt
    {
        InOrder(bt->left);//遍历左子树
        printf("%d",bt->key);//访问根结点
        InOrder(bt->right);//遍历右子树
    }
}

3.后序遍历

void PostOrder(BiTree bt)
{
    if(bt!=NULL)
    {
        PostOrder(bt->left);//遍历左子树
        PostOrder(bt->right);//遍历右子树
        printf("%d",bt->key);//访问根结点
    }
}

4.按层次遍历

void LevelOrderTraverse(BiTree T)//传入根指针
{
    if(T)
    {
        Queue *Q;//定义一个队列指针Q
        BiTree temp;//定义一个中间变量存取出来的指针
        InitQueue(Q);//队列初始化 置队空
        EnQueue(Q,T);
        while(!QueueEmpty(Q))//当队列Q非空时
        {
            temp=DeQueue(Q);//temp存队头指针
            printf("%d",temp->data);//打印队头指针指向的结点的key值
            if(temp->left)
                EnQueue(Q,temp->left);
            if(temp->right)
                EnQueue(Q,temp->right);

        }
    }
}

说明:
这里的队列初始化、入队、出队、判队空具体函数实现看“栈与队列”那一part,不同的是,这里的队列里存的元素类型为树的结点的指针类型BiTree。

遍历算法应用举例
  1. 统计二叉树中叶子结点的个数
    思路:
    先序(中序或后序)遍历二叉树,在遍历过程中查找叶子结点并计数。需在遍历算法中新增一个计数的操作,并把Visit操作(此处是printf)改为,若是叶子结点,则计数器加1.
void Leaves(BiTree bt)
{
    if(bt!=NULL)
    {
        if(bt->left==NULL&&bt->right=NULL)/*若是叶子结点时*/            
        count++;//计数器+1
        Leaves(bt->left);
        Leaves(bt->right);
    }
}

Notes:
1.count设为保存叶子结点数目的全局变量,调用之前初始化值为0
如果将Leaves函数返回值设成int,递归调用时有问题。
2.不论是先序、中序还是后序遍历,求叶子结点数目都是上面的代码,因为该树或其子树的根结点一定不是叶子结点,而if语句的操作只有满足是叶子结点才执行,且总的顺序是从左至右。

  1. 求二叉树的深度
    思路:
    首先分析二叉树的深度与它左右子树深度之间的关系。
    二叉树深度应为其左、右子树深度的最大值加1。按后序遍历编写深度函数,先分别求得左、右子树深度,再将其中的Visit操作(此处是printf)改为:
    深度=左、右子树深度最大值+1
    (因为要先求左子树和右子树的深度,再进行max操作,故按后序遍历)
int PostDepth(BiTree bt)
{
    int left_h,right_h,max_h;
    if(bt==NULL)
    return 0;//空树返回0
    left_h=PostDepth(bt->left);//求左子树深度
    right_h=PostDepth(bt->right);//求右子树深度
    max_h=left_h>right_h?left_h:right_h;//左子树和右子树深度较大值
    return max_h+1;//返回树的深度
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值