对给定的一棵二叉树进行递归和非递归的遍历操作

我们给出一棵确定的二叉树并进行递归和非递归的遍历比较

树的样子如下图所示:(下面的代码均是先递归后非递归)

给定的树的样子:
①头文件和结构体的定义:为了进行非递归时方便我们以链表的形式进行定义:

#include <stdio.h>
#include <stdlib.h>

typedef struct BiTNode
{
    char data;
    struct BiTNode *Left,*Right;
}*BiTree;

两种方式的唯一区别就是有一个头文件不同,因为非递归是基于栈的特点进行的,所以多了一个头文件,其余可以说是一模一样的

#include <stdlib.h>
#include<stack>
#include<iostream>
using namespace std;

typedef struct node
{
    char data;
    struct node *lchild,*rchild; 
}*BTNode;

②创建一开始给出的那棵二叉树:

BiTree CreatBinTree()
{
    BiTree BT[9];
    int i;
    for(i=0;i<9;i++) 
	{
        BT[i]=(BiTree )malloc(sizeof(struct BiTNode));
        BT[i]->data=(char)(65+i);
    }
    BT[0]->Left=BT[1]; BT[0]->Right=BT[2]; 
    BT[1]->Left=BT[3]; BT[1]->Right=BT[5];
	BT[2]->Left=BT[6]; BT[2]->Right=BT[8]; 
	BT[3]->Left=NULL;  BT[3]->Right=NULL;
    BT[4]->Left=NULL;  BT[4]->Right=NULL; 
    BT[5]->Left=BT[4]; BT[5]->Right=NULL;
    BT[6]->Left=NULL;  BT[6]->Right=BT[7]; 
    BT[7]->Left=NULL;  BT[7]->Right=NULL;
    BT[8]->Left=NULL;  BT[8]->Right=NULL;
    
    return BT[0];
}

两种方式几乎是一模一样了,存在的区别也就只是因为一开始结构体定义时用的变量名不同了。

BTNode CreatBinTree()
{
    BTNode BT[9];
    int i;
    for(i=0;i<9;i++) 
	{
        BT[i]=(BTNode )malloc(sizeof(struct node));
        BT[i]->data=(char)(65+i);
    }
    BT[0]->lchild=BT[1]; BT[0]->rchild=BT[2]; 
    BT[1]->lchild=BT[3]; BT[1]->rchild=BT[5];
	BT[2]->lchild=BT[6]; BT[2]->rchild=BT[8];
	BT[3]->lchild=NULL;  BT[3]->rchild=NULL;
	BT[4]->lchild=NULL;  BT[4]->rchild=NULL;  
	BT[5]->lchild=BT[4]; BT[5]->rchild=NULL;
    BT[6]->lchild=NULL;  BT[6]->rchild=BT[7]; 
    BT[7]->lchild=NULL;  BT[7]->rchild=NULL;
    BT[8]->lchild=NULL;  BT[8]->rchild=NULL;
    
    return BT[0];
}

③介绍一下主函数:

int main()
{
    BiTree BT = CreatBinTree();
    
    printf("左根右 中序遍历:");    
    InorderTraversal(BT);    printf("\n");
    
    printf("根左右 先序遍历:");   
    PreorderTraversal(BT);   printf("\n");
    
    printf("左右根 后序遍历:");  
    PostorderTraversal(BT);  printf("\n");
    
    printf("层次遍历:"); 
    LevelorderTraversal(BT); printf("\n");
    return 0;
}

可以看出没什么区别的:

int main()
{
    BTNode BT = CreatBinTree();
    
    printf("左根右 中序遍历:");    
    InOrderWithoutRecursion1(BT);    printf("\n");
    
    printf("根左右 先序遍历:");   
    PreOrderWithoutRecursion1(BT);   printf("\n");
    
    printf("左右根 后序遍历:");  
    PostOrderWithoutRecursion(BT);   printf("\n");
    
    printf("层次遍历:"); 
    LevelorderTraversal(BT);         printf("\n");
    return 0;
}

④前序遍历:

void PreorderTraversal( BiTree BT )
{
	if(BT)
	{
        printf(" %c",BT->data);
        PreorderTraversal(BT->Left);
        PreorderTraversal(BT->Right);
    }
}

传入的参数是一种类型的,前序遍历是根左右的顺序进行的,所以非递归时,在找到左子树最下边之前遇到的根节点要依次输出,然后再访问根节点的右子树。输出一个根节点,就把这个根节点更新为当前节点的左子树(也是一个根节点)即可。

void PreOrderWithoutRecursion1(BTNode root)
{
    if (root == NULL)
        return;
    BTNode p = root;
    stack<BTNode> s;
    while (!s.empty() || p)//栈不空或者p不空
    {
        while (p!=NULL)
        {
            cout << ' ' << p->data;
            s.push(p);
            p = p->lchild;
        }
        if (!s.empty())
        {
            p = s.top();
            s.pop();
            p = p->rchild;
        }
    }
}

⑤中序遍历:

void InorderTraversal( BiTree BT )
{
	if(BT!=NULL)
	{
		InorderTraversal(BT->Left);
		printf(" %c",BT->data);
		InorderTraversal(BT->Right);
	}
}

中序遍历(左根右)和前序遍历区别就是在遇到根节点是我们先进行存储而不是先输出,在遇到左子树最下边之后,取出栈顶元素,并输出,然后把结点更新为当前节点的右子树。

void InOrderWithoutRecursion1(BTNode root)
{
    if (root == NULL)
        return;
    stack<BTNode> s;
    while (!s.empty() || root)//栈不空或者p不空 
    {
        while (root!=NULL)
        {
            s.push(root);
            root = root->lchild;
        }
        if (!s.empty())
        {
            root = s.top();
            s.pop();
            cout << ' '<< root->data;
            root = root->rchild;
        }
    }
}

⑥后序遍历:

void PostorderTraversal( BiTree BT )
{
	if(BT)
	{
        PostorderTraversal(BT->Left);
        PostorderTraversal(BT->Right);
        printf(" %c",BT->data);
    }

}

后序遍历比上面两种稍微麻烦一点,因为顺序是左右根,所以在输出根节点时必须是在没有右子树或者右子树已经输出过之后才可以。所以这里我们用两个变量,一个用来表示当前访问结点,一个用来指示上次访问节点。
###如果是没有右子树或是右子树已经被访问过了,那么我们就输出根节点的数据域。
###如果不是,那么就需要把当前的根节点存储一下,然后去访问右子树。也就是之前删除了的栈顶元素再次存储起来。

void PostOrderWithoutRecursion(BTNode root)
{
    if (root == NULL)
        return;
        
    stack<BTNode> s;
    BTNode pCur, pLastVisit;
    pCur = root;
    pLastVisit = NULL;
    
    while (pCur)
    {
        s.push(pCur);
        pCur = pCur->lchild;
    }
  
    while (!s.empty())
    {
        pCur = s.top();
        s.pop();
        if (pCur->rchild == NULL || 
        pCur->rchild == pLastVisit)
        {
            cout << ' ' << pCur->data;
            pLastVisit = pCur;
        }
        else
        {
            s.push(pCur);
            pCur = pCur->rchild;
            while (pCur)
            {
                s.push(pCur);
                pCur = pCur->lchild;
            }
        }
    }
    cout << endl;
}

⑦层次遍历:

void LevelorderTraversal( BiTree BT )
{
	BiTree q[100];
    BiTree p;
    int head=0,tail=0;
    if(!BT) return;
    if(BT)
	{
        q[tail++]=BT; 
        while(tail!=head)
		{
            p=q[head++];
            printf(" %c",p->data);
            if(p->Left)     q[tail++]=p->Left;
            if(p->Right)    q[tail++]=p->Right;
        } 
    }
}

一模一样,层次遍历主观图中最好理解,这里我们设置两个变量,一个用来掌管输出,一个用来不断地访问结点。两个变量的增长速度不一样大,所以直到两者相等时我们结束输出即可。

void LevelorderTraversal( BTNode BT )
{
	BTNode q[100];
    BTNode p;
    int head=0,tail=0;
    if(!BT) return;
    if(BT)
	{
        q[tail++]=BT; 
        while(tail!=head)
		{
            p=q[head++];
            printf(" %c",p->data);
            if(p->lchild)     q[tail++]=p->lchild;
            if(p->rchild)    q[tail++]=p->rchild;
        } 
    }
}

⑧给出最后输出结果:
递归操作:
可以看出两者运行的时间还是有很大差距的,事实上递归的效率要更高一些。
在这里插入图片描述
⑨给出两种方式完整的代码:

#include <stdio.h>
#include <stdlib.h>

typedef struct BiTNode
{
    char data;
    struct BiTNode *Left,*Right;
}*BiTree;

BiTree CreatBinTree()
{
    BiTree BT[9];
    int i;
    for(i=0;i<9;i++) 
	{
        BT[i]=(BiTree )malloc(sizeof(struct BiTNode));
        BT[i]->data=(char)(65+i);
    }
    BT[0]->Left=BT[1]; BT[0]->Right=BT[2]; BT[1]->Left=BT[3]; BT[1]->Right=BT[5];
	BT[2]->Left=BT[6]; BT[2]->Right=BT[8]; BT[3]->Left=NULL;  BT[3]->Right=NULL;
    BT[4]->Left=NULL;  BT[4]->Right=NULL;  BT[5]->Left=BT[4]; BT[5]->Right=NULL;
    BT[6]->Left=NULL;  BT[6]->Right=BT[7]; BT[7]->Left=NULL;  BT[7]->Right=NULL;
    BT[8]->Left=NULL;  BT[8]->Right=NULL;
    return BT[0];
}

void InorderTraversal( BiTree BT );
void PreorderTraversal( BiTree BT );
void PostorderTraversal( BiTree BT );
void LevelorderTraversal( BiTree BT );

int main()
{
    BiTree BT = CreatBinTree();
    
    printf("左根右 中序遍历:");    InorderTraversal(BT);    printf("\n");
    printf("根左右 先序遍历:");   PreorderTraversal(BT);   printf("\n");
    printf("左右根 后序遍历:");  PostorderTraversal(BT);  printf("\n");
    printf("层次遍历:"); LevelorderTraversal(BT); printf("\n");
    return 0;
}

void InorderTraversal( BiTree BT )
{
	if(BT!=NULL)
	{
		InorderTraversal(BT->Left);
		printf(" %c",BT->data);
		InorderTraversal(BT->Right);
	}
}
void PreorderTraversal( BiTree BT )
{
	if(BT)
	{
        printf(" %c",BT->data);
        PreorderTraversal(BT->Left);
        PreorderTraversal(BT->Right);
    }
}
void PostorderTraversal( BiTree BT )
{
	if(BT)
	{
        PostorderTraversal(BT->Left);
        PostorderTraversal(BT->Right);
        printf(" %c",BT->data);
    }

}
void LevelorderTraversal( BiTree BT )
{
	BiTree q[100];
    BiTree p;
    int head=0,tail=0;
    if(!BT) return;
    if(BT)
	{
        q[tail++]=BT; 
        while(tail!=head)
		{
            p=q[head++];
            printf(" %c",p->data);
            if(p->Left)     q[tail++]=p->Left;
            if(p->Right)    q[tail++]=p->Right;
        } 
    }
}

#include <stdlib.h>
#include<stack>
#include<iostream>
using namespace std;

typedef struct node
{
    char data;
    struct node *lchild,*rchild; 
}*BTNode;

BTNode CreatBinTree()
{
    BTNode BT[9];
    int i;
    for(i=0;i<9;i++) 
	{
        BT[i]=(BTNode )malloc(sizeof(struct node));
        BT[i]->data=(char)(65+i);
    }
    BT[0]->lchild=BT[1]; BT[0]->rchild=BT[2]; BT[1]->lchild=BT[3]; BT[1]->rchild=BT[5];
	BT[2]->lchild=BT[6]; BT[2]->rchild=BT[8]; BT[3]->lchild=NULL;  BT[3]->rchild=NULL;
	BT[4]->lchild=NULL;  BT[4]->rchild=NULL;  BT[5]->lchild=BT[4]; BT[5]->rchild=NULL;
    BT[6]->lchild=NULL;  BT[6]->rchild=BT[7]; BT[7]->lchild=NULL;  BT[7]->rchild=NULL;
    BT[8]->lchild=NULL;  BT[8]->rchild=NULL;
    return BT[0];
}
//中序遍历 
void InOrderWithoutRecursion1(BTNode root)
{
    if (root == NULL)
        return;
    stack<BTNode> s;
    while (!s.empty() || root)//栈不空或者p不空 
    {
        while (root!=NULL)
        {
            s.push(root);
            root = root->lchild;
        }
        if (!s.empty())
        {
            root = s.top();
            s.pop();
            cout << ' '<< root->data;
            root = root->rchild;
        }
    }
}
//前序遍历: 
void PreOrderWithoutRecursion1(BTNode root)
{
    if (root == NULL)
        return;
    BTNode p = root;
    stack<BTNode> s;
    while (!s.empty() || p)//栈不空或者p不空
    {
        while (p!=NULL)
        {
            cout << ' ' << p->data;
            s.push(p);
            p = p->lchild;
        }
        if (!s.empty())
        {
            p = s.top();
            s.pop();
            p = p->rchild;
        }
    }
}   
//后序遍历
void PostOrderWithoutRecursion(BTNode root)
{
    if (root == NULL)
        return;
        
    stack<BTNode> s;
    BTNode pCur, pLastVisit;
    pCur = root;
    pLastVisit = NULL;
    
    while (pCur)
    {
        s.push(pCur);
        pCur = pCur->lchild;
    }
  
    while (!s.empty())
    {
        pCur = s.top();
        s.pop();
        if (pCur->rchild == NULL || pCur->rchild == pLastVisit)
        {
            cout << ' ' << pCur->data;
            pLastVisit = pCur;
        }
        else
        {
            s.push(pCur);
            pCur = pCur->rchild;
            while (pCur)
            {
                s.push(pCur);
                pCur = pCur->lchild;
            }
        }
    }
    cout << endl;
}
void LevelorderTraversal( BTNode BT )
{
	BTNode q[100];
    BTNode p;
    int head=0,tail=0;
    if(!BT) return;
    if(BT)
	{
        q[tail++]=BT; 
        while(tail!=head)
		{
            p=q[head++];
            printf(" %c",p->data);
            if(p->lchild)     q[tail++]=p->lchild;
            if(p->rchild)    q[tail++]=p->rchild;
        } 
    }
}
int main()
{
    BTNode BT = CreatBinTree();
    
    printf("左根右 中序遍历:");    InOrderWithoutRecursion1(BT);    printf("\n");
    printf("根左右 先序遍历:");   PreOrderWithoutRecursion1(BT);   printf("\n");
    printf("左右根 后序遍历:");  PostOrderWithoutRecursion(BT);  printf("\n");
    printf("层次遍历:"); LevelorderTraversal(BT); printf("\n");
    return 0;
}
写在最后:如果大家还不懂,可以搜我公共号:菜菜的学习日记,里面有更详细的解释。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只天蝎

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值