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

来源:互联网 发布:软件网站大全 编辑:程序博客网 时间:2024/05/18 14:25

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


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 0