1、树:n个结点的有限集,n=0时称为空树
n>0时:有且仅有一个特定的称为结点的根、其余结点可以分为m个互不相交的有限集
森林:是m棵互不相交的树的集合
2、树的存储结构
(1)双亲表示法:定义结构数组,存放树的结点,每个结点含两个域:数据域和双亲域
数据域:存放结点本身信息
双亲域:指示本结点的双亲结点在数组中的位置
特点:找双亲容易,找孩子难
类型描述
typedef structure PTNode{
TElemType data;
int parent; //双亲位置域
}PTNode;
树结构:
#define MAX_TREE_SIZE 100
typedef struct{
PTNode nodes[MAX_TREE_SIZE};
int r,n; //根结点的位置和结点个数
}PTree;
(2)孩子链表
把每个结点的孩子结点排列起来,看成是一个线性表,用单链表存储。
n个结点有n个孩子链表(叶子结点的孩子链表为空表),n个头指针又组成一个线性表,用顺序表存储

typedef struct CTNode{
int child;
struct CTNode *next;
}*ChildPtr;
typedef struct{
TElemType data;
ChildPtr first child; //孩子链表头指针
}CTBox;
树结构:
typedef struct{
CTBox nodes[MAX_TREE_SIZE];
int n,r; //结点数和根结点的位置
}CTree;
带双亲的孩子链表如图:

typedef struct CSNode{
ElemType data;
struct CSNode *firstchild,*nextsibling;
}CSNode,*CSTree;
3、树域二叉树的转换
由于树和二叉树都可以用二叉链表作存储结构,则以二叉链表作媒介可以到导出树和二叉树的一个对应关系。
(1)将树转换成二叉树:兄弟相连留长子
a)加线:在兄弟间加一条线。b)抹线:对每个结点,除了左孩子,去除其与其余孩子之间的关系
c)旋转:以树的根结点为轴心,将整树顺时针旋转45度





(1)森林中第一颗树的根结点


(1)满二叉树不一定是哈夫曼树(2)哈夫曼树中权越大的叶子离根越近 (3)具有相同带权结点的哈夫曼树不唯一


typedef struct{
int weight;
int parent,lch,rch;
}HTNode,*HuffmanTree;
哈夫曼树共有2n-1个结点,不使用0下标,数组大小为2n


(2)具体算法
void CreateHuffmanTree(HuffmanTree HT,int n){
if(n<=1) return;
m=2*n-1; //数组中共有m个元素
HT=new HTNode[m+1]; //0号单元未用,HT[m]表示根结点
for(I=1;i<=m;++i){. //将2n-1个元素的lcc\rch\parent置为0
HT[I].lch=0;
HT[I].rch=0;
HT[I].parent=0;
}
for(I=1;i<=n;++I)
cin>>HT[i].weight; //输入前n个元素的weight值
//初始化结束
for(I=n+1;i<=m;i++){. //合并产生n-1个结点--构造哈夫曼树
Select(HT,i-1,s1,s2). //在HT[k]中选择两个其双亲域为0且权值最小的结点,并返回他们在HT中的序号s1s2
HT[s1].parent=I;
HT[s2].parent=I; //分别从F中删除s1s2
HT[I].lch=s1;
HT[I].rch=s2; //s1s2分别作为I的左右孩子
HT[I].weight=HT[s1].weight+HT[s2].weight; //I的权值为左右孩子权值之和
}
}
10、哈夫曼编码
若将编码设计为长度不等的二进制编码,即让待穿传字符串中出现次数较多的字符采用尽可能短的编码,则转换的二进制字符串便可能减少。
关键:要设计长度不等的编码,则必须使任一字符的编码都不是另一个字符的编码的前缀
在哈夫曼树的每个分支上标0或1:结点左分支标0,右分支标1,把从根到每个叶子接的路径上的标号连接起来,作为该叶子代表的字符的编码。
两个问题:

***从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中
void CreateHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n){
HC=new char *[n+1]; //分配n个字符编码的头指针矢量
cd=new char [n]; //分配临时存放编码的动态数组空间
cd[n-1]='\0'; //编码结束符
for(I=1;i<=n;++i){. //逐个字符求哈夫曼编码
start=n-1; c=I; f=HT[I].parent;
while(f!=0){. //从叶子结点开始向上回溯,知道根结点
--start; //回溯一次start向前指一个位置
if(HT[f].child==c) cd[start]='0'; //结点c是f的左孩子,则生成代码0
else
cd[start]='1'; //结点c是f的右孩子,则生成代码
c=f;f=HT[f].parent; //继续向上回溯
} //求出第i个字符的编码
HC[I]=new char [n-start]; //为第I个字符串编码分配空间
strcpy(HC[I],&cd[start]); //将求得的编码从临时空间cd复制到HC的当前行中
}
delete cd; //释放临时空间
}
11、文件的编码和解码



729

被折叠的 条评论
为什么被折叠?



