DataStructure-6-树

6.1 树

6.1.1 树的定义

      树是n(n≥0)个结点的有限集合. 当n=0时,称为空树;任意一棵非空树满足一下条件:

 ①有且仅有一个特定的称为(root)的结点.

 ②当n>1时,除根结点之外的其余节点被分成m(m>0)个互不相交的有限集合T1,T2,T3,····,Tm,

其中每个集合又是一棵树,并称为这个根节点的子树(subtree).

                 

6.2树的基本术语

6.2.1 结点的分类(结点的度,树的度,叶子节点,分支节点)

 

6.2.2 节点间的关系(孩子节点,双亲节点,兄弟节点,祖先,子孙)

  

  


6.2.3其他关系(结点的层数,树的深度或高度,有序树,无序树,森林)

  

   

               


    线性结构与树结构比较:

        


6.3 树的存储结构

  详细解释: 点击打开链接


6.4  二叉树

   6.4.1 二叉树的定义

       二叉树是n(n≥0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根节点和

两棵互不相交的、分别称为根结点的左子树(left subtree)和右子树(right subtree)的二叉树组成.

 

     二叉树具有5种基本形态:

    ①空二叉树

    ②只有一个根结点

    ③根结点只有左子树

    ④根结点只有右子树

    ⑤根结点既有左子树又有右子树


    6.4.2 特殊二叉树

     1.斜树

      所有的结点都只有左子树的二叉树叫左斜树.

      所有的结点都只有右子树的二叉树叫右子树.

      这两者统称为斜树.

    

      2.满二叉树

     


       满二叉树的特点:

       ①叶子只能出现在最下一层.

       ②只有度为0和度为2的结点.

      

       3.完全二叉树

     

        完全二叉树的特点:

        ①叶子结点只能出现在最下两层,且最下层的叶子结点都集中在二叉树左侧连续位置.

        ②如果有度为1的结点,只可能有一个,且该结点只有左孩子.


    6.4.3 二叉树的基本性质

     

    


              性质 3:  在一棵二叉树中,如果叶子结点的个数为n0,度为2的结点个数为n2,

       则 n0=n2+1 .

      


      

      

      

      

      


 6.4.4 二叉树的实现


LinkBiTree.h


#ifndef LINKBITREE_H
#define LINKBITREE_H

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

typedef char DataType;

typedef struct BiNode
{
    DataType data;
    struct BiNode *lchild,*rchild;
}BiNode,*BiTree;

typedef struct SeqQueue
{
    int *data;
    int front;
    int rear;
}SeqQueue;

BiNode* InitBiTree(BiTree *bt); //初始化二叉树
void PreOrder(BiTree *bt); //前序遍历
void InOrder(BiTree *bt);  //中序遍历
void PostOrder(BiTree *bt); //后序遍历
void LeverOrder(BiTree *bt,SeqQueue *Q); //层序遍历
void Release(BiTree *bt); //释放二叉树


#endif


LinkBiTree.c

#include "LinkBiTree.h"

const QueueSize = 20;

/*以前序遍历的方式创建一棵二叉树*/
BiNode* InitBiTree(BiTree *bt)
{
    char ch;
    printf("Please Enter Data:\n");
    scanf("%c",&ch);
    getchar();  //去除‘\n'干扰
    //printf("ch:%c\n",ch);
    if(ch == ' ') //以‘ ’空格为结束标志
        (*bt) = NULL;
    else
    {
        *bt = (BiNode *)malloc(sizeof(BiNode));
        (*bt)->data=ch;
        (*bt)->lchild = InitBiTree(&((*bt)->lchild));
        (*bt)->rchild = InitBiTree(&((*bt)->rchild));
    }
    return *bt;
}

void PreOrder(BiTree *bt)
{
    if((*bt) == NULL)
        return ;
    else
    {
        printf("%c\n",(*bt)->data);
        PreOrder(&(*bt)->lchild);
        PreOrder(&(*bt)->rchild);
    }
}

void InOrder(BiTree *bt)
{
    if(*bt == NULL)
        return ;
    else
    {
        InOrder(&(*bt)->lchild);
        printf("%c\n",(*bt)->data);
        InOrder(&(*bt)->rchild);
    }
}

void PostOrder(BiTree *bt)
{
    if(*bt == NULL)
        return ;
    else
    {
        PostOrder(&(*bt)->lchild);
        PostOrder(&(*bt)->rchild);
        printf("%c\n",(*bt)->data);
    }
}

void LeverOrder(BiTree *bt,SeqQueue *Q)
{
    BiNode *p;
    //初始化一个队列
    Q->data = (int *)malloc(QueueSize*sizeof(int));
    if(Q->data == NULL)
        return ;
    //初始化空队列
    Q->front = Q->rear =  QueueSize - 1;
    /*如果二叉树为NULL,算法结束*/
    if((*bt) == NULL)
        return ;
    /*判断队列是否满*/
    if(Q->front == (Q->rear + 1)%QueueSize)
    {
        printf("Queue is full!\n");
        return ;
    }
    /*将树的根指针入队,由于队列data为int类型,因此将根指针强制类型转化为int型*/
    Q->data[++Q->rear]=(int)*bt;
    //printf("aaaaaa:%c\n",**bt);
    while(Q->front != Q->rear) //队列不为NULL
    {
        //出队
        //intf("aaaaaa:%c\n",Q->data[Q->front]);
        p=(BiNode*)Q->data[++Q->front];
        printf("%c\n",p->data);

        if(p->lchild != NULL) //左孩子入队
            Q->data[++Q->rear] = (int)p->lchild;
        if(p->rchild != NULL) //右孩子入队
            Q->data[++Q->rear] = (int)p->rchild;

    }
}

void Release(BiTree *bt)
{
    if(*bt != NULL)
    {
        Release(&(*bt)->lchild);
        Release(&(*bt)->rchild);
        free(*bt);
    }
}




main.c


#include "LinkBiTree.h"

int main(void)
{
    BiTree B;
    //初始化一棵扩展二叉树'AB D  C  ';
    InitBiTree(&B);
    //前序遍历
    printf("前序遍历:\n");
    PreOrder(&B);
    //中序遍历
    printf("中序遍历:\n");
    InOrder(&B);
    //后序遍历
    printf("后序遍历:\n");
    PostOrder(&B);

    SeqQueue Q;
    //层序遍历
    printf("层序遍历:\n");
    LeverOrder(&B,&Q);


    //释放二叉树
    Release(&B);


    return 0;
}


6.4.5 二叉树的非递归实现

LinkBiTree.h


#ifndef LINKBITREE_H
#define LINKBITREE_H

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

typedef char DataType;

typedef struct BiNode
{
    DataType data;
    struct BiNode *lchild,*rchild;
}BiNode,*BiTree;

//队列用于二叉树层序遍历
typedef struct SeqQueue
{
    int *data;
    int front;
    int rear;
}SeqQueue;//栈用于非递归实现
typedef struct SeqStack
{
    int *data;
    int top;
}SeqStack;


BiNode* InitBiTree(BiTree *bt,SeqStack *s); //初始化二叉树

void PreOrder(BiTree *bt,SeqStack *s); //前序遍历
void InOrder(BiTree *bt,SeqStack *s);  //中序遍历
void PostOrder(BiTree *bt,SeqStack *s); //后序遍历
void LeverOrder(BiTree *bt,SeqQueue *Q); //层序遍历
void Release(BiTree *bt,SeqStack *s); //释放二叉树

#endif


LinkBiTree.c


#include "LinkBiTree.h"

const QueueSize = 20;
const StackSize = 20;

/*以前序遍历的方式创建一棵二叉树*/
BiNode* InitBiTree(BiTree *bt,SeqStack *s)
{
    /*为二叉链表*bt申请空间,并将其赋值给p*/
    *bt = (BiTree)malloc(sizeof(BiNode));
    BiNode *p=*bt;
    BiNode *q;
    /*设置左右子树标志*/
    int tag[20];
    //初始化栈    
    s->data = (int *)malloc(StackSize*sizeof(int));
    s->top = -1;
    /*以‘@’为结束标志*/
    while(1)
    {
        char ch;
        printf("Please Enter Data:\n");
        scanf("%c",&ch);
        getchar();  //去除‘\n'干扰

        /*ch等于‘@’表示循环结束*/
        if(ch=='@')
        {
            break;
        }

        if(ch == ' ' )
        {
            /*如果tag为1,表示p此时应处于左子树位置,设置其左子树为NULL*/
            if(tag[s->top]==1)
            {
                p->lchild = NULL;
            }
            /*如果tag为2,表示p此时应处于右子树位置,设置其右子树为NULL*/
            if(tag[s->top]==2)
            {
                p->rchild = NULL;
            }

            // printf("NULL\n");
        }

        if(ch != ' ')
        {
            /*将ch赋值给q*/
            q=(BiNode *)malloc(sizeof(BiNode));
            if(q == NULL) //判断申请内存是否成功
                printf("Error!\n");
            q->data=ch;
            /*top=-1,说明此时输入的时根结点*/
            if(s->top==-1)
            {
                p->data=ch;  //根结点直接赋值  
                printf("root:%c \n",p->data);
            }
            /*tag == 1,说明此时要添加p的左子树,采用尾插法*/
            if(tag[s->top] == 1)
            {
                p->lchild = q; //将新结点q赋值给p的左子树
                p=q;  //p指针后移到q
                //printf("TopData:%c\n",((BiNode*)s->data[s->top])->data);
                //printf("lchild:%c \n",p->data);
                //printf("top:%d\n",s->top);
            }
            /*tag == 2,说明此时要添加p的右子树,采用尾插法*/
            if(tag[s->top] == 2)
            {
                p->rchild = q; //将新结点q赋值给p的右子树
                p=q;   //p指针后移到q
                //printf("TopData:%c\n",((BiNode*)s->data[s->top])->data);
                //printf("rchild:%c \n",p->data);
                //printf("top:%d\n",s->top);
            }
            /*将p入栈,将标志tag设为1*/
            s->data[++s->top]=(int)(p); //注意此处入栈的是p
            tag[s->top]=1;
      }else{
            /*当栈非空,且tag为2时,出栈*/
            while(s->top != -1 && tag[s->top]==2)
            {
                printf("kkkk:%c\n",((BiNode *)s->data[s->top--])->data);
                //printf("top:%d\n",s->top);
            }
            /*如果栈不为空,将栈顶标志tag设为2,并将栈顶元素赋值给p*/
            if(s->top != -1)
            {
                tag[s->top]=2;
                p=((BiNode *)s->data[s->top]);
                //printf("mmtop:%c\n",p->data);
            }
        }
    }
    return p;
}

//前序遍历非递归实现
void PreOrder(BiTree *bt,SeqStack *s)
{
    BiNode *p=*bt;
    /*初始化栈*/
    s->data = (int *)malloc(StackSize*sizeof(int));
    s->top = -1;
    /*循环直到bt为空且栈s为空*/
    while(p != NULL || s->top != -1)
    {
        while(p != NULL)
        {
            printf("%c \n",p->data);   //输出
            s->data[++(s->top)]=(int)p; //将*bt入栈
            p=p->lchild;   //继续遍历*bt的左子树
        }
        if(s->top != -1)
        {
            p = (BiNode *)s->data[(s->top)--];  //将栈顶元素弹出
            p = p->rchild;  //准备遍历*bt的右子树
        }
    }
}

//中序遍历非递归实现
void InOrder(BiTree *bt,SeqStack *s)
{
    BiNode *p=*bt;
    /*初始化栈*/
    s->data = (int *)malloc(StackSize*sizeof(int));
    s->top = -1;
    /*循环直到bt为空且栈s为空*/
    while(p != NULL || s->top != -1)
    {
        while(p != NULL)
        {
            s->data[++(s->top)]=(int)p; //将*bt入栈
            p=p->lchild;   //继续遍历*bt的左子树
        }
        if(s->top != -1)
        {
            p = (BiNode *)s->data[(s->top)--];  //将栈顶元素弹出
            printf("%c \n",p->data);   //输出
            p = p->rchild;  //准备遍历*bt的右子树
        }
    }

}

//后序遍历非递归实现
void PostOrder(BiTree *bt,SeqStack *s)
{
    BiNode *p=*bt;
    int tag[20];
    //初始化栈
    s->data = (int *)malloc(StackSize*sizeof(int));
    s->top = -1;

    //循环直到bt为空且栈s为空
    while((p != NULL) || (s->top != -1))
    {
        /*循环直到p为空*/
        while(p != NULL)
        {
            s->data[++(s->top)]=(int)p; //将p入栈
            tag[s->top]=1;      //将标志设为1
            p=p->rchild;   //继续遍历*bt的右子树
        }
        /*出栈并输出栈顶元素*/
        while(s->top != -1 && tag[s->top]==2)
        {
           /*书上写的如下注释两行,坑爹啊,死循环啊*/
           // p=(BiNode *)s->data[s->top--];
           // printf("%c \n",p->data);
            printf("%c \n",((BiNode *)s->data[s->top--])->data); //这是正确的
        }
        /*若栈非空,栈顶元素的标志改为2,准备遍历栈顶结点的左子树*/
        if(s->top != -1)
        {
            tag[s->top] = 2;
            p = ((BiNode *)s->data[s->top])->lchild;  //准备遍历*bt的左子树
        }
    }

}

//层序遍历非递归实现
void LeverOrder(BiTree *bt,SeqQueue *Q)
{
    BiNode *p;
    //初始化一个队列
    Q->data = (int *)malloc(QueueSize*sizeof(int));
    if(Q->data == NULL)
        return ;
    //初始化空队列
    Q->front = Q->rear =  QueueSize - 1;

    /*如果二叉树为NULL,算法结束*/
    if((*bt) == NULL)
        return ;
    /*判断队列是否满*/
    if(Q->front == (Q->rear + 1)%QueueSize)
    {
        printf("Queue is full!\n");
        return ;
    }
    /*将树的根指针入队,由于队列data为int类型,因此将根指针强制类型转化为int型*/
    Q->data[++Q->rear]=(int)*bt;
    //printf("aaaaaa:%c\n",**bt);
    while(Q->front != Q->rear) //队列不为NULL
    {
        //出队
        //intf("aaaaaa:%c\n",Q->data[Q->front]);
        p=(BiNode*)Q->data[++Q->front];
        printf("%c\n",p->data);

        if(p->lchild != NULL) //左孩子入队
            Q->data[++Q->rear] = (int)p->lchild;
        if(p->rchild != NULL) //右孩子入队
            Q->data[++Q->rear] = (int)p->rchild;

    }
}

void Release(BiTree *bt,SeqStack *s)
{
    BiNode *p=*bt;
    int tag[20];
    /*初始化栈*/
    s->data = (int *)malloc(StackSize*sizeof(int));
    s->top = -1;
    /*循环直到bt为空且栈s为空*/
    while(p != NULL || s->top != -1)
    {
        while(p != NULL)
        {
            s->data[++(s->top)]=(int)p; //将*bt入栈
            tag[s->top]=1;
            p=p->lchild;   //继续遍历*bt的左子树

        }
        while(s->top != -1 && tag[s->top]==2)
        {
            /*后序遍历出栈时,释放*/
            free((BiNode *)s->data[s->top]);
            //printf("%c \n",((BiNode *)s->data[s->top])->data); //这是正确的
            s->top--;

        }
        if(s->top != -1)
        {
            tag[s->top]=2;
            p = ((BiNode *)s->data[s->top])->rchild;  //准备遍历*bt的右子树
        }
    }

}



main.c


#include "LinkBiTree.h"

int main(void)
{
    BiTree B;
    SeqStack s;   
    SeqQueue Q;

    //初始化一棵扩展二叉树'AB D  C  @';
    InitBiTree(&B,&s);
    
    //前序遍历
    printf("前序遍历:\n");
    PreOrder(&B,&s);
    //中序遍历
    printf("中序遍历:\n");
    InOrder(&B,&s);  
    //后序遍历
    printf("后序遍历:\n");
    PostOrder(&B,&s);

    //层序遍历
    printf("层序遍历:\n");
     LeverOrder(&B,&Q);

    //释放二叉树
//    printf("aaaaaaaaa:%c\n",B->data);   
    Release(&B,&s);
//    printf("SUCCESS:%c\n",(B->lchild)->data);   
    //PreOrder(&B,&s);

    return 0;

}








6.5线索二叉树

点击打开链接


6.6树,森林与二叉树的转换

   6.6.1 树转换为二叉树


 6.6.2森林转换为二叉树


6.6.3 二叉树转换为树

 


6.6.4 二叉树转换为森林

                                                           图 6-11-5


6.6.5 树与森林的遍历

 (1)树的遍历

树的前序遍历 <==>二叉树的前序遍历

树的后序遍历<==>二叉树的中序遍历

 (2)森林的遍历

         6-11-5右侧三棵树的森林,后续遍历序列的结果是BCDAFEJHIG(即树的中序遍历)


6.7 二叉树的应用

哈夫曼树与哈夫曼编码

点击打开链接

6.8 树的应用

八枚硬币问题



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值