数据结构基础六-----之模块二《非线性结构==树的应用》

模块二:非线性结构----树


1.定义

    专业定义:

          1、有且只有一个称为根的结点。
          2、有若干个互不相交的子树,这些子树本身也是一个树。
     通俗说法:
          1、树是由结点和边组成。
          2、每个结点只有一个父节点,但可以有多个子节点。
          3、但有一个结点例外,该结点没有父节点,此节点称为根节点。

    专业术语:

          节点   父节点  子节点 子孙  堂兄弟  
          深度:

              从根节点到最底层节点的层数  称之为深度
              根节点是第一层。
          叶子节点:
              没有子节点的节点
          非终端结点:
              实际就是非叶子节点。(有子节点)
          度:
              子节点的个数称为度。(几个孩子)

          树的度:

              结点的最多孩子

2.分类

        一般树
             任意一个节点的子节点的个数都不受控制
        二叉树

            任意一个节点的子节点个数最多有两个,且子节点的位置不可变。
            左子树就是左子树,右子树就是右子树 。二叉树是一个有序树。

        二叉树分类:

                 ① 一般二叉树                   

                 ② 满二叉树

                         在不增加树的层数的前提下,无法再多添加一个节点的二叉树,就是满二叉树。
                  ③ 完全二叉树
                         如果只是删除了满二叉树最底层最右边的连续若干个节点,
                         这样形成的二叉树,就是完全二叉树。(满二叉树是完全二叉树的一个特例(一个都不删)
        森林
           N个互不相交的树的集合。

    

3. 树的存储

   3.1、二叉树的存储

        连续存储 [ 完全二叉树 ]

              一般二叉树要以数组的方式存储,要先转化成完全二叉树,因为如果只存有效节点(无论以哪种规则:先序,中序,后序),

                      则无法知道这个树的原本样子。

              优点:查找某个结点的父结点和子结点(也包括判断有没有子结点)速度很快
              缺点:耗用内存空间过大      

     链式存储

              数据域 指针域【  左指针(左孩子) 右指针(右孩子)】
              N个结点只浪费N+1个指针空间(空指针);
        

    3.2、一般树的存储

            ① 双亲表示法
                   求父节点方便
                       
              孩子表示法

                     求子节点方便

              


           ③  双亲孩子表示法

                      求父节点和子节点都很方便。

            

---------------------------------------------------以上三种操作困难    

          ④ 二叉树表示法(常用)

                把一个普通树转换成二叉树来存储。

      


                具体方法:
                    设法保证任意一个节点的
                        左指针域指向它的第一个孩子
                        右指针域指向它的下一个兄弟

                    只要能满足此条件,就可以将一个普通树转换成二叉树

                    一棵普通树转化成二叉树,根节点肯定没有右子树。

        ⑤森林的存储
                 先把森林转化为二叉树,再存储二叉树

4.二叉树操作

       4.1 、遍历

             ① 先序遍历
                  (1) 先访问 根节点
                  (2) 先序遍历左子树

                  (3) 先序遍历右子树


              ② 中序遍历
                  (1)中序遍历左子树
                  (2)访问 根节点

                  (3)中序遍历右子树


              ③ 后序遍历
                  (1)后序遍历左子树
                  (2)后续遍历右子树

                  (3)访问根节点


            无论是中序遍历还是怎样,都是以 根节点为参照点来定义的。     

      4.2、已知两种遍历序列求原始二叉树

                (1)先序+中序


                (2)后序+中序


                但是通过先序和后序是无法还原出原始的二叉树的。

5.树的应用

        树是数据库中数据组织的一种重要形式。
        操作系统子父进程关系的本身就是一个树
        面向对象语言中 类的继承关系本身就是一棵树。
        赫夫曼树: 一个实物有N种取值,每种取值的概率是不一样的.如何求最优


实例: 实现二叉树 先序 中序 后序

#include<stdio.h>
#include<malloc.h>

struct BTNode{
    char data;
    struct  BTNode * pLchild;    //p是指针    L是左    child是孩子
    struct     BTNode * pRchild;     
};

struct BTNode * CreateBTree(void);
void PreTraverseBTree(struct BTNode* pT);
void InTraverseBTree(struct BTNode* pT);
void PostTraverseBTree(struct BTNode* pT);

int main(void){
    
    struct BTNode * pT = CreateBTree();
    
    PreTraverseBTree(pT);
    printf("\n");
    InTraverseBTree(pT);
    printf("\n");
    PostTraverseBTree(pT);
    
    return 0;
}

//先序遍历 根左右
void PreTraverseBTree(struct BTNode* pT){//根左右 
    
    if(NULL != pT){
        printf("%c",pT->data);
        if(NULL != pT->pLchild){
            PreTraverseBTree(pT->pLchild);
        }
        
        if(NULL != pT->pRchild){
            PreTraverseBTree(pT->pRchild);    
            //pT->pLchild 可以代表整个左子树     
        }        
    }         
}

//中序遍历 左根右
void InTraverseBTree(struct BTNode* pT){//左根右 
    
    if(NULL != pT){
        
        if(NULL != pT->pLchild){
            InTraverseBTree(pT->pLchild);
        }
        printf("%c",pT->data);  
        if(NULL != pT->pRchild){
            InTraverseBTree(pT->pRchild);    
            //pT->pLchild 可以代表整个左子树     
        }        
    }         
}

//后续遍历 左右根
void PostTraverseBTree(struct BTNode* pT){
    
    if(NULL != pT){
        
        if(NULL != pT->pLchild){
            PostTraverseBTree(pT->pLchild);
        }
        
        if(NULL != pT->pRchild){
            PostTraverseBTree(pT->pRchild);    
            //pT->pLchild 可以代表整个左子树     
        }
        
        printf("%c",pT->data);          
    }         
}

//创建一颗树
struct BTNode * CreateBTree(){
    struct BTNode* pA = (struct BTNode *)malloc(sizeof(struct BTNode));
    struct BTNode* pB = (struct BTNode *)malloc(sizeof(struct BTNode));
    struct BTNode* pC = (struct BTNode *)malloc(sizeof(struct BTNode));
    struct BTNode* pD = (struct BTNode *)malloc(sizeof(struct BTNode));
    struct BTNode* pE = (struct BTNode *)malloc(sizeof(struct BTNode));
    
    pA->data = 'A';
    pB->data = 'B';
    pC->data = 'C';
    pD->data = 'D';
    pE->data = 'E';
    
    pA->pLchild = pB;
    pA->pRchild = pC;
    pB->pLchild = pB->pRchild = NULL;
    pC->pLchild = pD;
    pC->pRchild = NULL;
    pD->pLchild = NULL;
    pD->pRchild = pE;
    pE->pLchild = pE->pRchild = NULL;
    
    return pA;
}



















    


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值