数据结构全攻略--二叉树胡子眉毛一把抓

来源:互联网 发布:top域名百度收录吗 编辑:程序博客网 时间:2024/04/28 12:00

    通过前几篇博客的讨论,已经把几种常见的二叉树概括了一遍,不过讲解的都是基本的知识点,涉及到了很多种特殊的二叉树,对于这些特殊的二叉树都需要熟知它们之间的概念,学习需要反复,温故而知新,那今天从头再咀嚼下几种特殊的二叉树之间的关系。

    胡子眉毛一把抓,这好像不是一个好词,撇开它的词性不说,想想这个问题,怎么做到胡子眉毛一把抓呢?相信聪明的你已经找到了答案,往下看答案在下面。

    那和今天要说的二叉树有什么关系吗?恩,的确没有什么关系,但却是今天要说的一种学习方法--编织知识网。知识网和生活中常见的网有什么区别,在我看来是没有什么区别的,只不过知识网是平常所见网的一种抽象罢了。想要编织知识网就必须要有结点,而为了把结点串联起来就必须知道结点之间的一些关系,这种关系可以是相互之间的联系,也可以是相互之间的对立。结点和关系让你想到了什么,是不是很像数据库模型中概念模型的ERER模型中的实体对应着结点,关系对应着联系。

    所以如何将胡子眉毛一把抓呢,那就是把它们连到一起,无论我们想要抓眉毛还是抓胡子,都会牵扯到另一部分,不就做到了一把抓了吗。那现在调用大脑使用面向对象抽象的方法,得到胡子和眉毛的关系,抽象出了毛发,毛发就是它们之间的关系。

 到底这几种二叉树有哪些关系

 1、平衡二叉树

    先从平衡二叉树说起。平衡二叉树要么是一课空树,或者是具有下列性质的二叉树。它的左子树和右子树都是平衡二叉树,且左子树和右子树的高度之差绝对值不超过1,如下图的二叉平衡树:

平衡二叉树结点定义:

#include<stdlib.h>typedef    int     Status;typedef    int     ElemType;typedef    int     KeyType;typedef struct BSTNode{ElemType      data;int           bf;         //结点平衡因子BSTNode       *lchild, *rchild;   //左右孩子指针}BSTNode, *BSTree;Status InitBSTree(BSTree &BT)   //初始化{//操作结果:构造一个空的动态查找表BTBT=NULL;return OK;}//InitBSTree

 

2、完全和满二叉树

    接着来看满二叉树和完全二叉树,上篇博客对满二叉树和完全二叉树进行了讨论,从它们两者集合的范畴上来说,满二叉树属于一种特殊的完全二叉树。另外从完全二叉树的特点上来看,它只允许最后两层有叶子结点,所以它的左子树和右子树的高度差绝对值不超过1,如下图:

 

3、二叉排序树

    再看二叉排序树,二叉排序树的引入是为了提高查找效率,它采用了二分法的查找方法,对树进行构造,父结点的权值要大于左子树所有结点的权值,并小于所有右子树结点的权值。并且只有在树的形态比较均匀的情况下,查找效率才能达到最佳。另外二叉排序树的结构是由结点给出的构造顺序决定的,即同样的结点会因构造顺序的不同而构造出不同的二叉排序树,如下图。

     所以二叉排序树和平衡二叉树部分相关,它们之间的交集是查找效率最佳的二叉排序树。

 

二叉排序树的结点定义:

Typedef struct Tnode{int data;/*结点的关键字值*/struct Tnode *lchild,*rchild;/*指向左、右子树的指针*/ }Tnode,*Bitree;


 

4、线索二叉树

    要看线索二叉树,就要从二叉树的遍历说起了,它的提出是为了保存在遍历的动态过程中得到的结点的信息。

    二叉树的遍历实质上是对一个非线性结构进行线性化的过程,线性化后的二叉树就好像线性表一样,使每个结点在这些线性序列中有了直接前驱和直接后继。但在二叉链表存储结构中,只能找到一个节点的左右孩子,而不能得到任一结点在任一遍历中的前驱和后继,所以为了保存这些信息引入了线索二叉树。从它的差生原因看,线索二叉树也可以和这几种树之间有交集,这样提高了存储空间的利用率,但从它的集合范畴看,任何一种二叉树都会有它的线索二叉树,所以它的范畴是最大的。

线索链表的结点定义:

typedef int ElemType;struct ThreNode{ ElemType data;  ThreNode *lch,*rch;  int ltag,rtag;}/*ltag=0 lchild是指向结点的左孩子的指针ltag=1 lchild是指向结点的前趋的左线索。rtag=0 rchild是指向结点的右孩子的指针rtag=1 rchild是指向结点的后继的右线索针;*/


 

5、最优二叉树

    上篇博客我们提到最优二叉树的引入是为了提高通信效率,所以从这点看它和其它几种结构没有什么交集。那从它的构成看,每次取权值最小的两个来构造,得到的结构可能会有类似于平衡二叉树、完全二叉树、满二叉树的结构,所以它要和他们三者之间有交集。

所以最终的几种特殊的二叉树关系图如下:

最优二叉树创建算法:

void createHTree(HuffmanTree HT,char *c,int *w,int n)/*数组c[0...n-1]和w[0..n-1]存放了n个字符及其概率,构造哈弗曼树HT*/{          int i, s1,s2;if(n<=1) return;for(int i;i<=n;i++){       /*根据n个权值构造n棵只有根结点的二叉树*/HT[i].ch=c[i-1];HT[i].weight=w[i-1];HT[i].parent=HT[i].lchild=HT[i].rchild=0;}/*for*/for(;i<2*n;++i){       /*初始化*/HT[i].parent=0;HT[i].lchild=0;HT[i].rchild=0;}/*for*/for(i=n+1;i<2*n;i++){/*从HT[1..i-1]中选择parent为0且weight最小的两棵树,其序号为s1和s2*/select(HT,i-1,s1,s2);HT[s1].parent=i;HT[s2].parent=i;HT[i].lchild=s1;HT[i].rchild=s2;HT[i].weight=HT[s1].weight+HT[s1].weight;}/*for*/}/*createHTree*/


 

6、结语

    经过上面的比较分析,把几种特殊的二叉树结构进行了一次区分和联系,这样就把几种特殊的二叉树结构连在了一起,这样做的目的是为了减少记忆量,同时也更加深刻的理解了这几种二叉树结构,在学习时不妨也尝试下这种比较分类的方法,要知道单纯的记忆是很让人头疼的一件事,还不如花一些时间整理它们之间的关系,这样到哪儿也不会忘记了。另外还加了一些基本的结点代码,这些都是很基础的东西。

原创粉丝点击