二叉树的创建以及先序,中序,后序递归法遍历,普通循环遍历

一:创建

既然有先序法遍历,那应该也有先序法创建.二叉链的数据模型是:

typedef struct BinaryTree

{ char data;

struct BinaryTree* lchild;

struct BinaryTree* rchild;

}BT;

下面就用二叉链的数据类型,创建一个二叉树

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 10
#include <string.h>
typedef struct BinaryTree
{
    char data;
    struct BinaryTree* lchild;
    struct BinaryTree* rchild;
}BT;

void Creat_Tree(BT** T)
{
    if((*T))
    {
        char input = 0;
        printf("请输入你想要存储的字符:>");
        scanf("%c",&input);
        getchar();
        if(input != 'Q')
        {
            *T = (BT*)malloc(sizeof(BT));//判断你的输出,如果不是Q,就创建一个结点来存储你的输出
            (*T)->data = input;//结点赋值
            Creat_Tree(&((*T)->lchild));//创建结点的左孩指针,并根据你的输出,判断是否创建左孩子结点
            Creat_Tree(&((*T)->rchild));//创建结点的右孩指针,并根据你的输出,判断是否创建右孩子结点
        }
        else
        {
            (*T) = NULL;//如果你输出Q,那么给当前结点赋空值,不再向下添加元素
        }
    }

}
int main()
{
    BT* T;
    Creat_Tree(&T);
    printf("%c\n",T->data);
    printf("%c\n",T->lchild->lchild->data);
    printf("%c\n",T->rchild->data);
    return 0;
}

这样,一个二叉树就创建完成,运行起来,输入值.

此刻,二叉树实例已经生成,下面我们就针对这个二叉树进行遍历 ,二叉树的遍历主流:先序遍历,中序遍历,后序遍历

二:二叉树的遍历

1:递归遍历,先序,中序,后序

先序:通过指针,找到结点后.先对该结点的值进行操作(赋值,取值,打印等等),然后,再对左孩子指针指向的结点进行操作,一直到左孩子指针为空后,再对右孩子进行操作,通俗点讲,就是先操作结点的值域,再操作结点的左孩子,最后操作结点的右孩子的一个顺序D->L->R

同理中序为:L->D->R,后序为:L->R->D

下面就这三种递归方式的代码实现:

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 10
#include <string.h>
typedef struct BinaryTree
{
    char data;
    struct BinaryTree* lchild;
    struct BinaryTree* rchild;
}BT;

void Creat_Tree(BT** T)
{
    if((*T))
    {
        char input = 0;
        printf("请输入你想要存储的字符:>");
        scanf("%c",&input);
        getchar();
        if(input != 'Q')
        {
            *T = (BT*)malloc(sizeof(BT));//判断你的输出,如果不是Q,就创建一个结点来存储你的输出
            (*T)->data = input;//结点赋值
            Creat_Tree(&((*T)->lchild));//创建结点的左孩指针,并根据你的输出,判断是否创建左孩子结点
            Creat_Tree(&((*T)->rchild));//创建结点的右孩指针,并根据你的输出,判断是否创建右孩子结点
        }
        else
        {
            (*T) = NULL;//如果你输出Q,那么给当前结点赋空值,不再向下添加元素
        }
    }

}

void PreOrder(BT* T)//先序遍历
{
    if(T)
    {
        printf("%c ",T->data);//取数据
        if(T->lchild)PreOrder(T->lchild);//递归处理左孩子
        if(T->rchild)PreOrder(T->rchild);//递归处理右孩子
    }

}
void MidOrder(BT* T)//中序遍历
{
    if(T)
    {
        if(T->lchild)PreOrder(T->lchild);
        printf("%c ",T->data);
        if(T->rchild)PreOrder(T->rchild);
    }

}
void PostOrder(BT* T)//后序遍历
{
    if(T)
    {
        if(T->lchild)PreOrder(T->lchild);
        if(T->rchild)PreOrder(T->rchild);
        printf("%c ",T->data);
    }

}
int main()
{
    BT* T;
    Creat_Tree(&T);
    printf("先序遍历的结果是:\n");
    PreOrder(T);//先序遍历
    printf("\n");
    printf("中序遍历的结果是:\n");
    MidOrder(T);//中序遍历
    printf("\n");
    printf("后序遍历的结果是:\n");
    PostOrder(T);//后序遍历
    return 0;
}

然后,我们运行起来,先创建,再遍历,得到的结果是:

 结果没有问题,但我们从代码里看到,三个排序方法,其实很相似.只是取数据的时机不相同而已,确实,不管哪种排序,代码遍历每个结点的路线是不变的,变化的只是在哪个时间去取结点的数据,所以三种排序的时间度和空间度是相同的.

前面的方法都是用递归的思想,就是用栈来保存每个节点的参数的变量.每个结点都要新开辟一个栈,如果二叉树的深度太大,那么这些个方法的执行效率就大打折扣了.只是要保存路过的结点的数据,我也可以自己开一个栈用来保存数据,利用栈的先进后出的特点,再从里面取出来就好了,这样效率也高了不少,所以到底用哪种方法,要看具体的情况而定.下面就介绍一下普通的循环方式来遍历二叉树(用中序的思想)

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 10
#include <string.h>
typedef struct BinaryTree//二叉树,结点类型
{
    char data;
    struct BinaryTree* lchild;
    struct BinaryTree* rchild;
}BT;

typedef struct Stack//栈结构体
{
    int* top;//栈顶指针
    int* basic;//栈底指针
    int sz;//栈的大小
}S;

void Creat_Tree(BT** T)
{
    if((*T))
    {
        char input = 0;
        printf("请输入你想要存储的字符:>");
        scanf("%c",&input);
        getchar();
        if(input != 'Q')
        {
            *T = (BT*)malloc(sizeof(BT));//判断你的输出,如果不是Q,就创建一个结点来存储你的输出
            (*T)->data = input;//结点赋值
            Creat_Tree(&((*T)->lchild));//创建结点的左孩指针,并根据你的输出,判断是否创建左孩子结点
            Creat_Tree(&((*T)->rchild));//创建结点的右孩指针,并根据你的输出,判断是否创建右孩子结点
        }
        else
        {
            (*T) = NULL;//如果你输出Q,那么给当前结点赋空值,不再向下添加元素
        }
    }

}

void Creat_Stack(S* SP)//创建并初始化一个栈
{
    SP->basic = malloc(sizeof(int)*MAXSIZE);
    if(!SP->basic)//判断申请内存有没有成功
    {
        printf("创建失败");
        return;
    }
    else
    {
        SP->top = SP->basic;//栈顶指针=栈底指针,栈为空
        SP->sz = MAXSIZE;
    }

}

void Push_Stack(S* SP, BT* a)
{
    if(SP->top - SP->basic < SP->sz)
    {
        *(SP->top) = a;
        SP->top++;
    }
    else
    {
        printf("栈已经满了");
    }
}

int Pop_Stack(S* SP)
{
    if(SP->top - SP->basic > 0)
    {
        SP->top--;
        return *(SP->top);
    }
    else
    {
        printf("栈已经空了");
    }
}

void Traversal(BT* T, S* SP)
{
    while(T||SP->top - SP->basic > 0)//传入的结点不为空,栈不为空
    {
        if(T)
        {
            Push_Stack(SP,T);//结点地址入栈
            T = T->lchild;//指针指向他的左孩子
        }
        else
        {
            T = Pop_Stack(SP);//如果左孩子为空,就取得该结点的数据
            printf("%c ", T->data);
            T = T->rchild;//然后指向右孩子
        }

    }
}

int main()
{
    BT* T;
    S SP;
    Creat_Tree(&T);
    Creat_Stack(&SP);//创建一个顺序栈,用来存储结点的地址
    printf("循环遍历的结果是:\n");
    Traversal(T,&SP);


    return 0;
}

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值