树
树是数据结构内很重要的一种结构。不过我们此处不深究,仅讨论二叉树,线索二叉树,哈夫曼树(最优树)。
二叉树
定义:(1)空树;(2)只有一个根节点;(3)有左右两个子树,并且子树也是一颗二叉树(如图)。
性质:
1.第 i 层上最多有
2
i
−
1
2^{i-1}
2i−1个节点.
2.深度为k的树最多有 2 k 2^k 2k-1个节点,我们称之为满二叉树,满二叉树在底层从右向左减少n个节点,此时称为完全二叉树。
3.度为0的结点的个数为度为2的节点个数加一, n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1.
4.n个节点的完全二叉树的深度为[ l o g 2 n log_2n log2n]+1。注释:[x]表示不超过x的最大整数,也就是向下取整。
5.节点序号为 i ,在子节点存在的情况下,节点的序号为2i和2i+1
遍历方式
1.先序遍历:先访问根节点,再访问左子树然后是右子树。
2.中序遍历:先访问左子树,再访问根节点然后再右子树。
3.后序遍历:先访问左子树,再访问右子树然后是根节点。
先序中序,后序中序能唯一的确定唯一一个二叉树
还有其他三种遍历方式 : 只需将以上三种方式的左和右换位置即可
存储结构
1.顺序存储结构(由于太浪费内存,所以说一般不用)
2.链式存储结构:利用二叉链表来组成的二叉树(有n个节点的二叉树,含有n+1个空链域)。
树
#include<stdio.h>
typedef struct Lnode{
char data;
struct Lnode *left,*right;
}Lnode,*linkLnode;
//创建树
void setleaf(linkLnode &L){
char data;
scanf("%c",&data);
if(data=='#'){
L=NULL;
return;
}
Lnode *w=new Lnode;
L=w;
L->data=data;
setleaf(L->left);
setleaf(L->right);
}
//先序遍历
void xian(linkLnode L){
if(L==NULL)
return;
else
printf("%c\t",L->data);
xian(L->left);
xian(L->right);
}
//中序遍历
void zhong(linkLnode L){
if(L==NULL)
return;
zhong(L->left);
printf("%c\t",L->data);
zhong(L->right);
}
//后序遍历
void hou(linkLnode L){
if(L==NULL)
return;
hou(L->left);
hou(L->right);
printf("%c\t",L->data);
}
//度为0的节点个数
int ling(linkLnode L){
int i;
if(L!=NULL)
i=ling(L->left)+ling(L->right);
else
return 0;
if(L->left==NULL && L->right==NULL)
i=i+1;
return i;
}
//度为1的节点个数
int yi(linkLnode L){
int i;
if(L!=NULL)
i=yi(L->left)+yi(L->right);
else
return 0;
if((L->left==NULL && L->right!=NULL) ||(L->left!=NULL && L->right==NULL))
i=i+1;
return i;
}
//从数的最左边,最底层,开始往高处,往右侧检测
//度为2的节点个数
int er(linkLnode L){
int i;
if(L!=NULL)
i=er(L->left)+er(L->right);
else
return 0;
if(L->left!=NULL && L->right!=NULL)
i=i+1;
return i;
}
//计算树的深度
int deep(linkLnode L){
if(L==NULL)
return 0;
if( deep(L->left) > deep(L->right) )
return deep(L->left)+1;
else
return deep(L->right)+1;
}
void main(){
linkLnode L;
L=new Lnode;
L->left=L->right=NULL;
printf("请以先序遍历的方式输入(#代表此位置无值)\n");
setleaf(L);
printf("创建成功\n");
printf("先序遍历:\n");
xian(L);
printf("\n中序遍历:\n");
zhong(L);
printf("\n后序遍历:\n");
hou(L);
printf("\n度为0的节点个数为:%d\n",ling(L));
printf("\n度为1的节点个数为:%d\n",yi(L));
printf("\n度为2的节点个数为:%d\n",er(L));
printf("\n树的深度为:%d\n",deep(L));
}
线索二叉树
线索二叉树与二叉树大致一样,只不过是将空链域充分利用起来,便于查找每个节点的前驱和后继。
代码仅是中序线索二叉树
#include<stdio.h>
typedef struct Lnode{
char data;
struct Lnode *left,*right;
int zuo,you;
}Lnode,*linkLnode;
//创建树
void setleaf(linkLnode &L){
char data;
scanf("%c",&data);
if(data=='#'){
L=NULL;
return;
}
Lnode *w=new Lnode;
L=w;
L->data=data;
setleaf(L->left);
setleaf(L->right);
}
//中序遍历
void zhong(linkLnode &L){
if(L==NULL)
return;
zhong(L->left);
zhong(L->right);
if(L->left==NULL)
L->zuo=0;
else
L->zuo=1;
if(L->right==NULL)
L->you=0;
else
L->you=1;
}
//设置线索
void guo(linkLnode &L){
Lnode *m,*n;
m=L->left;n=L->right;
printf("此时进入到了%c\n",L->data); //输出一些过程,便于观察
if(L->zuo!=0){
while(m->you==1)
m=m->right;
m->right=L;
printf("m的指向值为%c,m的右侧为%c\n",m->data,m->right->data);
guo(L->left);
}
printf("此时返回到了%c\n",L->data);
if(L->you!=0){
while(n->zuo==1)
n=n->left;
n->left=L;
printf("n的指向值为%c,n的左侧为%c\n",n->data,n->left->data);
guo(L->right);
}
printf("准备返回上一层\n");
return;
}
void zhongappear(linkLnode L){
Lnode *m;
m=L;
while(1){
while(m->zuo==1)
m=m->left;
if(m==NULL)
break;
printf("%c\t",m->data);
if(m->you==0){
printf("%c\t",m->right->data);
m=m->right->right;}
else
m=m->right;
if(m==NULL){
printf("圆满结束\n");
break;}
}
}
void main(){
linkLnode L,S;
L=new Lnode;
S=new Lnode;
S->you=0;S->zuo=1;
S->left=L;
L->left=L->right=NULL;
printf("请以先序遍历的方式输入(#代表此位置无值)\n");
setleaf(L);
printf("创建成功\n");
zhong(L);
guo(L);
printf("\n中序遍历结果:\n");
zhongappear(L);
}
哈夫曼树
又名最优树,就是指带权路径最小的数,也是二叉树的一种,仅包含度为0或者2的节点。
构造方法
取权值最小的两个节点,作为额外一个空节点的左右两个孩子,然后取第三小的权值节点,与这颗树组成新树,以此类推,构成一颗哈夫曼树。权值越大的节点离根节点越近。
森林
一棵树为树,两棵树及以上则称为森林
树
前面介绍的仅是二叉树,一个节点只能有两个孩子,对于树的话则是一个节点可以有无数个孩子
存储结构
1.双亲表示法:节点存储在线性表中,每个节点除了存数data外,还存储父亲的下标,这种方法查找节点的父亲很容易,查找孩子的话则不简便。
2.孩子表示法:用的是一个顺序表,然后链接许多链表构成分,连表内包含的是其孩子。
3.孩子兄弟表示法:此方法等于说是将树化为一颗二叉树,孩子在左,兄弟在右,处理方法将于二叉树类似了,颇为常用(根节点的右孩子必为空)。
遍历
1.先根遍历:等于二叉树的前序遍历,应为根节点的右孩子为空。
2.后根遍历:等于二叉树的中序遍历
森林
两颗及以上的树构成森林,森林也可以转化为一棵树,规则也是孩子在左,兄弟在右
遍历
1.先序遍历:等于二叉树的先序
2.中序遍历:等于二叉树的中序