【数据结构】二叉树

目录

1.介绍

        1.1.二叉树

        1.2.满二叉树

2.二叉树的存储结构

        2.1.二叉树的顺序存储

        2.2.二叉树的链式存储

3.二叉树的建立

4.二叉树的遍历

        4.1.二叉树的递归遍历

        4.2.二叉树的非递归遍历

        4.3.二叉树的层次遍历


1.介绍

        1.1.二叉树

        什么是二叉树,想要知道二叉树,我们需先知道树的概念 。树(tree) 是n(n>=0)个结点的有限集。n=0时称为空树。在任何一棵非空树中:1. 有且只有一个特定的称为 根(root) 的结点;2. 当n>1时,其余结点可分为m(m>0)个 互不相交 的有限集,其中每一个集合又是一棵树,并且成为 根的子树(subtree),树是一种一对多的结构。

 二叉树,就是度最多只有2的树,通俗的讲,就是每个结点最多只能有两个分支。

        1.2.满二叉树

        满二叉树就是满足以下性质的二叉树:

        1.满二叉树中第 i 层的结点数为 2n-1 个。

        2.深度为 k 的满二叉树必有 2k-1 个结点 ,叶子数为 2k-1。

        3.满二叉树中不存在度为 1 的结点,每一个分支点中都两棵深度相同的子树,且叶子结点都在最底层。

2.二叉树的存储结构

        二叉树的存储结构分为两种,顺序存储和链式存储。

        2.1.二叉树的顺序存储

        二叉树的存储结构利用数组的形式存储,并按照满二叉树的顺序排序,没有的地方存0即可。

输入方式按照层次自左向右依次输入即可,即是按照满二叉树的顺序。

#include<stdio.h>
#define Max 100
typedef int Sqbitree[Max];

 

        2.2.二叉树的链式存储

        二叉树的链式存储结构通过链表的形式实现,首先,作为二叉树,需要两个分支分别代表下一个结点,我们将两个结点分别命名为左、右孩子,以及本身的数据域

typedef struct _bisq
{
    int date;                        //数据域
    struct _bisq *lchild;            //左孩子
    struct _bisq *rchild;            //右孩子
}BiNode;

3.二叉树的建立

        二叉树的建立分为三种:前序建立,中序建立,以及后序建立。前序建立就是先输入根结点,再输入左子树,最后输入右子树,即根左右;中序建立就是左根右,后序建立就是左右根

这里抽出前序建立进行评说:

二叉树的前需建立通过递归的形式实现,对每一个分支进行建立,直到输入为空(自定义一个字符)

void BiTreeCreate(BiTree *p)   //二叉树的前序建立
{
    char ch;                //数据域初始化
    scanf("%c",&ch);
    if ( ch == '#' )        //判断是否终止
        p = NULL;
    else
    {
        p = (BiTree*)malloc(sizeof(BiTree));        //给该结点赋予空间
        if ( !p )            
            exit(0);
        p->data = ch;                   //前序中序后序的区别就在于此行代码位置
        BiTreeCreate(p->lchild);        //若上行代码位于这就是中序,后序就在下一行
        BiTreeCreate(p->rchild);
     /*不要小看代码的位置,由于递归的原因,一个位置的变化引起的因果是很大的*/
    }
}

4.二叉树的遍历

        4.1.二叉树的递归遍历

        二叉树的递归遍历分为前序遍历,中序遍历和后序遍历,代码比较简单,看一下基本都能理解:

void PreorderTraverse(BiTree *p)        //遍历函数
{
    if ( p == NULL )                //判断树是否为空
        return ;
    else
    {
        printf("%c",p->data);        //遍历
        PreorderTraverse(p->lchild);        //左孩子遍历
        /*先序中序后序的区别就是printf函数在哪一行的区别,在第一行就是先序,
        在第二行就是中序,在第三行就是后序*/
        PreorderTraverse(p->rchild);        //右孩子遍历
    }
}

        4.2.二叉树的非递归遍历

        非递归遍历如何实现?主要是运用栈先进后出的思想进行遍历,既然要用到栈,我们就需要一些有关栈的函数

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define Max 9999


typedef struct _Sq
{
    char data;
    int Cishu;        //后序遍历需要
    struct _Sq *lchild,*rchild;
}BiTree;

typedef struct _stack
{
    BiTree *elements[Max];
    int top;
}SetStack;

SetStack S;

void setnull()   //初始化栈
{
    S.top = 0;
}

void push(BiTree *p)            //栈入函数
{
    S.elements[S.top++]=p;
}

BiTree *pop()                    //栈出函数
{
    return S.elements[--S.top];
}

前序非递归遍历:根左右,扫描二叉树,将根存入栈,再存入左子树,在对左子树进行上一步操作,直到左子树遍历完成,存入右子树,重复操作进行遍历(由于前序和中序思想类似,不再逐个解释)

void preorder(BiTree *p)  //前序非递归遍历 (根左右)
{
    BiTree *t = p;
    while ( t != NULL || S.top !=0 )            //若结点不为空或栈不为空时
    {
        while ( t != NULL )                    //若结点不为空,重复操作,对每一个子树
        {
            printf("%4c",t->data);                //遍历根结点
            push(t);                              //根结点入栈
            t = t->lchild;                        //访问左子树
        }
        if ( S.top != 0 )                        //若栈不为空
        {
            t = pop();                            //出栈上一个存入的结点
            t = t->rchild;                        //对上一个结点的右子树进行遍历
        }
    }
}
void inorder(BiTree *p)  //中序非递归遍历(左根右)
{
    BiTree *t = p;
    while ( t != NULL || S.top != 0 )
    {
        while ( p != NULL )
        {
            push(t);
            p = p->lchild;
        }
        if ( S.top != 0 )
        {
            t = pop();
            printf("%4c",p->data);
            t = t->rchild;
        }
    }
}

后序非递归遍历:特殊处理,由于后序遍历会经过两次根结点,所以会多出一个cishu变量,在第一次经过时不对其进行遍历,直至第二次才遍历

void laorder(BiTree *p)   //后序非递归遍历
{
    BiTree *t = p;
    while ( t != NULL && S.top != 0 )
    {
        while ( t != NULL )
        {
            t->Cishu = 1;
            push(t);
            t = t->lchild;
        }
        if ( S.top != 0 )
        {
            t = pop();
            if ( t->Cishu == 1 )  //第一次被访问
            {
                t->Cishu++;
                push(t);
                t = t->rchild;
            }
            else
            {
                if ( t->Cishu == 2 )  //第二次被访问,制空,防止陷入死循环
                {
                    printf("%4c",t->data);
                    t = NULL;
                }
            }
        }
    }

        4.3.二叉树的层次遍历

        二叉树的层次遍历主要通过队列先进先出的思想实现:所以我们需要一些有关队列的函数

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define Max 9999
typedef struct _Sq{
    char date;
    struct _Sq *lchild,*rchild;
}BiTree;



//实现思路:利用队列先进先出的思想

typedef struct _queue{
    BiTree *elements[Max];
    int front;
    int real;
}SetQueue;

SetQueue *p;


void InitQueue(){            //队列初始化
    p->front = p->real = 0;
}

void Push (BiTree* s) {        //入队
    p->elements[++p->real] = s;
}

BiTree* Pop() {            //出队
    return p->elements[++p->front];
}

int empty() {            //判断是否队列为空
    return p->real == p->front;
}
void levelorder() {
    BiTree* t;
    if (t != NULL) {        //如果树不为空
        Push(t);            //将当前结点入队
    }
    while (!empty()) {        //判断队列是否空
        t = Pop();            //出队
        printf("%4c",t->date);        //遍历
        if (t->lchild != NULL) {        
            Push(t->lchild);        //如果左子树不为空,入队
        }
        if (t->rchild != NULL) {
            Push(t->rchild);        //如果右子树不为空,入队
        }
    }
}

//由于队列先进先出的思想,所有的子树就会排在根结点的后面,按照层次遍历就实现了
//不能理解的可以用笔举个实例,按照代码进行操作

 以上就为二叉树的一些遍历方法和建立方法~

如果有什么错误请指出~笔者会及时更改

多多担待~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值