十二、树


 


1.定义

专业定义:

  1. 有且只有一个称为根的节点

  2. 有若干个互不相交的子树,这些子树本身也是一颗树

通俗定义:

  1. 树是由节点和边组成

  2. 每个节点只有一个父节点但可以有很多个子节点

  3. 但有一个节点例外,该节点没有父节点,此节点称为根节点

专业术语:

节点 父节点 子节点

子孙 堂兄弟

深度:

从根节点到最底层节点的层数称之为深度

根节点是第一层

叶子节点:

没有子节点的节点

非终端节点:

实际就是非叶子节点

度:

子节点的个数称为度

2.分类

一般树

任意一个节点的子节点的个数都不受限制

二叉树

任意一个节点的子节点个数最多两个,且子节点的位置不可更改

分类:

一般二叉树

满二叉树

在不添加树层数的前提下,无法再多添加 一个节点的二叉树就是满二叉树

完全二叉树

如果只是删除了满二叉树最底层最右边的连
续若干个节点,这样形成的二叉树就是完全二叉树

森林

n个互不相交的树的集合

树的存储

二叉树的存储

连续存储【完全二叉树】

优点:

查找某个节点的父节点和子节点(也包括判断有没有子节点)速度很快

缺点:

耗用内存空间过大

链式存储

一般树的存储

双亲表示法

求父节点方便

孩子表示法

求子节点方便

双亲孩子表示法

求父节点和子节点和方便

二叉树表示法

把一个普通树转化为二叉树来存储

具体转换方法:

设法保证任意一个节点的

左指针域指向它的第一个孩子

右指针域指向它的下一个兄弟

只要能满足此条件,就可以吧一个普通书转化为二叉树

一个普通树转化成二叉树一定没有右子树

森林的存储

先把森林转化为二叉树,在存储二叉树

把第二棵树视为第一棵树的兄弟

3.操作

遍历

先序遍历

先访问根节点

再先序访问左子树

再先序访问右子树

 

中序遍历

中序遍历左子树

再访问根节点

再中序遍历右子树

后序遍历

中序遍历左子树

中序遍历右子树

再访问根节点

 

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

通过先序和中序 或者 中序和后序我们可以还原出原始的二叉树

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

换种说法:

只有通过先序和中序,或通过中序和后序才能唯一地确定一个二叉树

4.应用

树是数据库中数据组织一种重要形式

操作系统子父进程的关系本身就是一棵树

面向对象语言中类的继承关系

赫夫曼树

赫夫曼编码是最基本的压缩编码方法

5.算法演示

链式二叉树算法

要存放的是这样一个二叉树

定义链式二叉树结构体

  1. typedef struct BTNode

  2. {

  3. char data;

  4. struct BTNode * pLChild;//定义类型为struct BTNode的指针

  5. struct BTNode * pRChild;

  6. } * PBTNODE;

创建树的方法

  1. PBTNODE CreateBTree(void)

  2. {

  3. PBTNODE pA = (struct BTNode *)malloc(sizeof(struct BTNode));

  4. PBTNODE pB = (struct BTNode *)malloc(sizeof(struct BTNode));

  5. PBTNODE pC = (struct BTNode *)malloc(sizeof(struct BTNode));

  6. PBTNODE pD = (struct BTNode *)malloc(sizeof(struct BTNode));

  7. PBTNODE pE = (struct BTNode *)malloc(sizeof(struct BTNode));

  8. pA->data = ‘A’;

  9. pB->data = ‘B’;

  10. pC->data = ‘C’;

  11. pD->data = ‘D’;

  12. pE->data = ‘E’;

  13. pA->pLChild = pB;

  14. pA->pRChild = pC;

  15. pB->pLChild = pB->pRChild = NULL;

  16. pC->pLChild = pD;

  17. pC->pRChild = NULL;

  18. pD->pLChild = NULL;

  19. pD->pRChild = pE;

  20. pE->pLChild = pE->pRChild = NULL;

  21. return pA;

  22. }

前序遍历的方法

  1. void PreTraverseBTree(PBTNODE pT)

  2. {

  3. if (NULL != pT)

  4. {

  5. printf(“%cn”, pT->data);

  6. if (NULL != pT->pLChild)

  7. {

  8. PreTraverseBTree(pT->pLChild);

  9. }

  10. if (NULL != pT->pRChild)

  11. {

  12. PreTraverseBTree(pT->pRChild);

  13. }

  14. }

  15. //pT->pLChild;可以代表整个左子树

  16. }

中序遍历的方法

  1. void InTraverseBTree(PBTNODE pT)

  2. {

  3. if (NULL != pT)

  4. {

  5. if (NULL != pT->pLChild)

  6. {

  7. InTraverseBTree(pT->pLChild);

  8. }

  9. printf(“%cn”, pT->data);

  10. if (NULL != pT->pRChild)

  11. {

  12. InTraverseBTree(pT->pRChild);

  13. }

  14. }

  15. }

后序遍历的方法

  1. void PostTraverseBTree(PBTNODE pT)

  2. {

  3. if (NULL != pT)

  4. {

  5. if (NULL != pT->pLChild)

  6. {

  7. PostTraverseBTree(pT->pLChild);

  8. }

  9. if (NULL != pT->pRChild)

  10. {

  11. PostTraverseBTree(pT->pRChild);

  12. }

  13. printf(“%cn”, pT->data);

  14. }

  15. }


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!