数据结构 二叉树的遍历

看了一下午的英语和磁共振,写个博客轻松一下,

你们是想看MYSQL还是单片机还是数据结构还是安卓app?

配着和平精英车载音乐priceless,开始创作

就聊聊树和二叉树吧

树的逻辑表示方法有四种:树形表示法,文氏图表示法,凹入表示法,括号表示法。最后一种括号表示法我们写程序用的到。

树的高度了,结点个数了,存储结构了,这些知识自己看书,不再赘述,因为这是基本理论,基本算法也自己看,我们要讲就讲进阶算法。

前方高能!!!

先序,中序和后序遍历递归算法

基本内容

先序遍历访问节点的顺序是根节点-左儿子-右儿子

1 void PreOrderTraversal(BinTree BT)
2 {
3     if( BT ) 
4     {
5         printf(“%d\n”, BT->Data);        //对节点做些访问比如打印         
6         PreOrderTraversal(BT->Left);     //访问左儿子
7         PreOrderTraversal(BT->Right);    //访问右儿子
8     }
9 }

由递归代码可以看出,该递归为尾递归(尾递归即递归形式在函数末尾或者说在函数即将返回前)。尾递归的递归调用需要用栈存储调用的信息。

中序遍历的遍历路径与先序遍历完全一样。其实现的思路也与先序遍历非常相似。其主要的不同点是访问节点顺序不同:

中序遍历是访问完所有左儿子后再访问根节点,最后访问右儿子,即为左儿子-根节点-右儿子。

  递归实现的代码如下:

 

void InOrderTraversal(BinTree BT)
{
    if(BT)
    {
        InOrderTraversal(BT->Left);
        printf("%d\n", BT->Data);
        InOrderTraversal(BT->Right);
    }
}

后序遍历与中序遍历,先序遍历的路径也完全一样。主要的不同点是后序遍历访问节点的顺序是先访问左儿子和右儿子,

最后访问节点,即左儿子-右儿子-根节点。

  递归实现思路与中序遍历和先序遍历相似,代码如下:

void PostOrderTraversal(BinTree BT)
{
    if (BT)
    {
        PostOrderTraversal(BT->Left);
        PostOrderTraversal(BT->Right);
        printf("%d\n", BT->Data);
    }
}

基础知识结束

现在问题来了,为什么有递归的也有非递归的,他们有什么区别

如果我使用递归算法,毫无疑问,简洁,简单,易懂。但是缺点就是是函数调用自身,而函数调用是有时间和空间的消耗的:每一次函数调用,都需要在内存栈中分配空间以保存参数、返回地址以及临时变量,而往栈中压入数据和弹出数据都需要时间。调用栈可能会溢出,其实每一次函数调用会在内存栈中分配空间,而每个进程的栈的容量是有限的,当调用的层次太多时,就会超出栈的容量,从而导致栈溢出。那到时候你怎么办?对吧。

要不要分析一下非递归算法?我分析一个,然后其他的自己看书。

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

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;  //转向右子树
        }
    }
}

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

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

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

简单来说,

看这个图,访问顺序是ABDGCEF。根节点是A,毋庸置疑,进栈再访问,A进去又出来了。接着到左右孩子B,C,C先进去,因为从先序遍历次序根左右来说,栈是先进后出,左孩子先访问,所以左孩子后进去,好了,然后B出去了,D进栈,再出栈。G进栈,再出栈。好了,这个时候C终于可以出栈了,接着F,E进栈,E,F出栈。完美结束。

中序非递归的话,教你一个判断自己错没错的小技巧,那个根节点最后一定是在最中间,如果你不是,那恭喜你,一定错了。

后序非递归的话,简单粗暴的说,根节点和他的左孩子的左孩子们进栈,但是先别访问,让左孩子们都先出栈,右孩子们进栈,右孩子们再出栈,最后根节点出栈。

我感觉都是一类,一样的,中序和后序甚至比先序还好理解。加油吧!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值