树、二叉树、查找算法总结
树
思维导图(我用画图软件画的太难看啦。。。)
树的基本性质
结点
1、分支结点:树中度不为零的结点。
2、叶子结点:度为零的结点。
3、孩子结点:在一棵树中,每个结点的后继结点。
4、双亲结点:在一棵树中,每个结点的前一个结点。
5、兄弟结点:具有同一双亲结点的结点。
次序
1、有序树:若树中各结点的子树是按照一定的次序从左向右安排的,且相对次序是不能随意变换的;则为有序树。
2、无序树:若非有序树则为无序树。
树的基本运算
先根遍历
概念:访问根结点,按照从左到右的顺序先根遍历根结点的每一棵子树。
后根遍历
概念:按照从左到右的顺序后根遍历根结点的每一棵子树。
层次遍历
概念:层次遍历的过程是从根结点开始按从上到下、从左到右的次序访问树中的每一个结点。
树的储存结构
双亲存储结构
1、概念:是一种顺序储存结构,用一组连续空间存储树的所有结点,同时在每个结点中附设一个伪指针指示其双亲结点的位置。(一般将根结点的双亲结点位置
设置为-1。)
2、代码:
typedef struct { ElemType data; int parent; }PTree[MaxSize];
typedef struct
{
ElemType data;
int parent;
}PTree[MaxSize];
3、优缺点:利用了每个结点(除了根结点)只有唯一的双亲结点的性质,所以求某个双亲结点十分容易,但求某个结点的孩子结点时需要遍历整个储存结构。
孩子链存储结构
1、特点:每个结点不仅包含结点数,还包括指向所有孩子结点的指针。
2、代码:
typedef struct { ElemType data; struct node* sons[MaxSize]; }TSonNode;
typedef struct
{
ElemType data;
struct node* sons[MaxSize];
}TSonNode;
3、优缺点:在寻找孩子结点时十分方便,但查找某结点的双亲结点比较费时,且当树的度比较大时存在较多的空指针域。
孩子兄弟链存储结构
1、概念:是为每个结点设计3个域,即一个数据元素域,一个指向该结点的左边第一个孩子结点的指针域、一个指向该结点的下一个兄弟结点的指针域。
2、代码:
tyoedef struct node { ElemType data; struct tnode *hp; struct tnode *vp; }TSBNode;
tyoedef struct node
{
ElemType data;
struct tnode *hp;
struct tnode *vp;
}TSBNode;
3、优缺点:可方便的实现树和二叉树的相互转换,但从当前结点查找双亲结点比较困难。
二叉树
1、概念:二叉树是n(n>=0)个结点的一个有限集合,该集合或者为空集(称为空二叉树),或者是由一个根节点加上两棵互不相交的、分别称为左子树和右子树的二叉树组成。
2、特点:每个节点最多有两棵子树,即二叉树不存在度大于2的节点。二叉树的子树有左右之分,其子树的次序不能颠倒。
3、特殊的二叉树:
(1)满二叉树:高度为h,并且含有(2^h)-1个结点的二叉树。
(2)完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
4、二叉树的一些特殊性质:
性质1 在二叉树的第 i 层上至多有 2^(i-1)个 结点(i>=1)
性质2 深度为k的二叉树至多有2^k-1个结点(k≥1)。
性质3 在任意-棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则no=n2+1。
性质4:具有n个结点的完全二叉树的深度为【log2n】+1(【x】表示不大于x的最大整数)。
性质5 :对完全二叉树按从上到下、从左到右的顺序依次编号1,2,…,n,则有一下关系:
(1) 当i>1时,结点i的双亲结点标号为向下取整(i/2),即当i为偶数时,其双亲结点的编号为i/2,他是双亲结点的左孩子;当i为奇数时,其双亲结点的编号为(i-1)/2,他是双亲结点的右孩子。
(2)当2i<=n时,结点i的左孩子编号为2i,否则无左孩子。
(3) 当2i+1<=n时,结点i的右孩子编号为2i+1,否则无右孩子。
5、二叉树的存储结构:
(1)顺式存储结构:
1)顺式存储的类型声明:
typedef ElemType SqBinTree[MaxSize];
2)顺式存储实际上就是用一组地址连续的存储单元来存放二叉树的数据元素。
3)优缺点:具有顺序存储的结构的固有缺陷使二叉树的插入、删除等运算十分不方便。
(1)链式存储结构:
1)链式存储的类型声明:
typedef struct node {ElemType data; struct node * lchild; struct node * rchild; }BTNode;
typedef struct node
{ElemType data;
struct node * lchild;
struct node * rchild;
}BTNode;
2)顺式存储实际上就是用一组地址连续的存储单元来存放二叉树的数据元素。
3)优缺点:具有顺序存储的结构的固有缺陷使二叉树的插入、删除等运算十分不方便。
6、二叉树的遍历:遵循某种次序,遍历二叉树中的所有节点,使得每个节点被访问一次,并且每个结点仅访问一次的过程。(它是二叉树最基本的运算,是二叉树中所有其他的运算实现的基础)。
(1)先序遍历:先访问根节点,再访问左子树,最后访问右子树。
void PreOrederTraverse(BinTree T) { if(T==NULL) return; printf("%c",T->data); PreOrderTraverse(T->lchild); PreOrderTraverse(T->rchild);
void PreOrederTraverse(BinTree T)
{
if(T==NULL)
return;
printf("%c",T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
(2)中序遍历:先访问左子树,再访问根节点,最后访问右子树。
void InOrederTraverse(BiTree T) { if(T==NULL) return; InOrderTraverse(T->lchild); printf("%c",T->data); InOrderTraverse(T->rchild); }
void InOrederTraverse(BiTree T)
{
if(T==NULL)
return;
InOrderTraverse(T->lchild);
printf("%c",T->data);
InOrderTraverse(T->rchild);
}
(3)后序遍历:先访问左子树,再访问右子树,最后访问根节点。
void PostOrederTraverse(BiTree T) { if(T==NULL) return; PostOrderTraverse(T->lchild); PostOrderTraverse(T->rchild); printf("%c",T->data); }
void PostOrederTraverse(BiTree T)
{
if(T==NULL)
return;
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c",T->data);
}
(4)层次遍历:同一层中按左子树再右子树的次序遍历,从根节点层到叶节点层访问。
树和二叉树的森林的转化
1、森林转二叉树
(1)、首先把每棵树转换为二叉树。
(2)、第一棵二叉树不动,从第二棵二叉树开始,每一次把后一棵二叉树的根结点作为前一棵二叉树的根结点的右孩子,并用线连接起来。
2、树转二叉树
(1)、加线。首先在所有的兄弟结点之间加一条线。
(2)、去线。然后树中的每个结点,只保留它与第一个孩子结点的连线,删除其他孩子结点之间的连线。
(3)、调整。最后以树的根结点为轴心,将整个树调节一下(第一个孩子是结点的左孩子,兄弟转过来的孩子是结点的右孩子)
3、二叉树转树
(1)、加线。若某结点X的左孩子结点存在,则将这个左孩子的右孩子结点、右孩子的右孩子的右孩子结点。。。都作为结点X的孩子。将结点X与这些右孩子结点用线连接起来。
(2)、去线。删除原二叉树中所有结点与其右孩子结点的连线。
(3)、层次调整。
4、二叉树转换为森林
(ps:假如一棵二叉树的根节点有右孩子,则这棵二叉树能够转换为森林,否则转换为一棵树。)
转换规则:
(1)、从根节点开始,若右孩子存在,则把与右孩子结点的连线删除。再查看分离后的二叉树,若其根节点的右孩子存在,则连续删除。直到所有这些根结点与右孩子的连线都删除为止。
(2)、将每棵分离后的二叉树转换为树。
哈夫曼树
1、特点:哈夫曼树是一种带权路径长度最短的二叉树,也称为最优二叉树。
2、相关概念:(1)路径长度:从树一个结点到另一个结点之间的分支构成两个结点之间的路径,路径上的分支数目称作路径长度。
(2)树的路径长度:从树的根到每一个结点的路径长度之和。
(3)带权路径长度:树中所有叶子结点的带权路径长度之和。
3.构造哈夫曼树的大致步骤:
(1)首先将所有左,右子树都为空的作为根节点。
(2)然后在森林中选出两棵根节点的权值最小的树作为一棵新树的左,右子树,且置新树的附加根节点的权值为其左,右子树上根节点的权值之和。注意,左子树的权值应小于右子树的权值。
(3)从森林中删除这两棵树,同时把新树加入到森林中。
(4)重复2,3步骤,直到森林中只有一棵树为止,这棵树就是哈夫曼树。
4.哈夫曼编码
哈夫曼编码的步骤:
(1)对于给定的n个权值{W1,W2,W3,...,Wi,...,Wn}构成n棵二叉树的初始集合F= {T1,T2,T3,...,Ti,...,Tn},其中每棵二叉树Ti中只有一个权值为Wi的根结点,它的左右子树均为空。(为方便在计算机上实现算 法,一般还要求以Ti的权值Wi的升序排列。)
(2)在F中选取两棵根结点权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树的根结点的权值之和。
(3)从F中删除这两棵树,并把这棵新的二叉树同样以升序排列加入到集合F中。
(4)重复二和三两步,直到集合F中只有一棵二叉树为止。
我的问题
1、二叉树的查找方法掌握不清楚。
2、哈夫曼树理解不透彻。
(不知道是哪一步出了错误,我的博客插入的代码没有换行,但新手上路,毫无办法,故在下方重新附了一次代码,希望老师手下留情,万分感谢。)