/敬竖弊/哈夫曼树的构造哈夫曼树,哈夫曼编码 *
//* * * * * * * * * * * * * * * * * * * * * * * *
#include <dos.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{unsigned int weight //结点权值
unsigned int parent,lchild,rchild//结点的父指针,左右孩子指针
}HTNode,*HuffmanTree //动态分配数组存储哈夫曼树
typedef char **HuffmanCode//动态分配数组亮族存储哈夫曼编码表
void CreateHuffmanTree(HuffmanTree &,unsigned int*,int )//生成一棵哈夫曼树
void HuffmanCoding(HuffmanTree,HuffmanCode &,int ) //对哈夫曼树进行编码
void PrintHuffmanCode(HuffmanCode,unsigned int*,int)//显示哈夫曼编码
void Select(HuffmanTree,int,int&,int&)//在数组中寻找权值最小的两个结点
void main()
{HuffmanTree HT //哈夫曼树HT
HuffmanCode HC //哈夫曼编码表HC
int n,i//n是哈夫曼树叶子结点数
unsigned int *w//w存放叶子结点权值
char j='y'
textbackground(3) //设定屏幕颜色纤羡
textcolor(15)
clrscr()
//程序解说
printf("本程序将演示构造哈夫曼树.\n")
printf("首先输入叶子结点数目.\n例如:8\n")
printf("然后输入每个叶子结点的权值.\n")
printf("例如:5 29 7 8 14 23 3 11\n")
printf("程序会构造一棵哈夫曼树并显示哈夫曼编码.\n")
printf(" 5---0110\n 29---10\n 7---1110\n 8---1111\n 14---110\n")
printf(" 23---00\n 3---0111\n 11---010\n")
while(j!='N'&&j!='n')
{printf("请输入叶子结点数目:")
scanf("%d",&n) //输入叶子结点数
if(n<=1) {printf("该数不合理!\n")continue}
w=(unsigned int*)malloc(n*sizeof(unsigned int))//开辟空间存放权值
printf("请输入各叶子结点的权值:\n")
for(i=0i<ni++) scanf("%d",&w[i]) //输入各叶子结点权值
CreateHuffmanTree(HT,w,n) //生成哈夫曼树
HuffmanCoding(HT,HC,n) //进行哈夫曼编码
PrintHuffmanCode(HC,w,n) //显示哈夫曼编码
printf("哈夫曼树构造完毕,还要继续吗?(Y/N)")
scanf(" %c",&j)
}
}
void CreateHuffmanTree(HuffmanTree &HT,unsigned int *w,int n)
{//w存放n个结点的权值,将构造一棵哈夫曼树HT
int i,m
int s1,s2
HuffmanTree p
if(n<=1) return
m=2*n-1 //n个叶子结点的哈夫曼树,有2*n-1个结点
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode))//开辟2*n各结点空间,0号单元不用
for(p=HT+1,i=1i<=n++i,++p,++w) //进行初始化
{p->weight=*w
p->parent=0
p->lchild=0
p->rchild=0
}
for(i<=m++i,++p)
{p->weight=0
p->parent=0
p->lchild=0
p->rchild=0
}
for(i=n+1i<=m++i) //建哈夫曼树
{Select(HT,i-1,s1,s2)
//从HT[1...i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2
HT[s1].parent=iHT[s2].parent=i//修改s1和s2结点的父指针parent
HT[i].lchild=s1HT[i].rchild=s2//修改i结点的左右孩子指针
HT[i].weight=HT[s1].weight+HT[s2].weight//修改权值
}
}
void HuffmanCoding(HuffmanTree HT,HuffmanCode &HC,int n)
{//将有n个叶子结点的哈夫曼树HT进行编码, 所编的码存放在HC中
//方法是从叶子到根逆向求每个叶子结点的哈夫曼编码
int i,c,f,start
char *cd
HC=(HuffmanCode)malloc((n+1)*sizeof(char *))//分配n个编码的头指针向量
cd=(char *)malloc(n*sizeof(char)) //开辟一个求编码的工作空间
cd[n-1]='\0' //编码结束符
for(i=1i<=n++i) //逐个地求哈夫曼编码
{start=n-1 //编码结束位置
for(c=i,f=HT[i].parentf!=0c=f,f=HT[f].parent) //从叶子到根逆向求编码
if(HT[f].lchild==c) cd[--start]='0' //若是左孩子编为'0'
else cd[--start]='1' //若是右孩子编为'1'
HC[i]=(char *)malloc((n-start)*sizeof(char)) //为第i个编码分配空间
strcpy(HC[i],&cd[start])//将编码从cd复制到HC中
}
free(cd)//释放工作空间
}
void PrintHuffmanCode(HuffmanCode HC,unsigned int *w,int n)
{//显示有n个叶子结点的哈夫曼树的编码表
int i
printf("HuffmanCode is :\n")
for(i=1i<=ni++)
{printf(" %3d---",w[i-1])
puts(HC[i])
}
printf("\n")
}
void Select(HuffmanTree HT,int t,int&s1,int&s2)
{//在HT[1...t]中选择parent不为0且权值最小的两个结点,其序号分别为s1和s2
int i,m,n
m=n=10000
for(i=1i<=ti++)
{if(HT[i].parent==0&&(HT[i].weight<m||HT[i].weight<n))
if(m<n)
{n=HT[i].weights2=i}
else {m=HT[i].weights1=i}
}
if(s1>s2) //s1放较小的序号
{i=s1s1=s2s2=i}
}
#include<string.h>#include<stdlib.h>
#include<stdio.h>
int m,s1,s2
typedef struct {
unsigned int weight
unsigned int parent,lchild,rchild
}HTNode,*HuffmanTree//动态分配数组存储哈夫曼树
typedef char *HuffmanCode//动态分配数组存储哈夫曼编码表
void Select(HuffmanTree HT,int n) {
int i,j
for(i = 1i <= ni++)
if(!HT[i].parent){s1 = ibreak}
for(j = i+1j <= nj++)
if(!HT[j].parent){s2 = jbreak}
for(i = 1i <= ni++)
if((HT[s1].weight>HT[i].weight)&&(!HT[i].parent)&&(s2!=i))s1=i
for(j = 1j <= nj++)
if((HT[s2].weight>HT[j].weight)&&(!HT[j].parent)&&(s1!=j))s2=j
}
void HuffmanCoding(HuffmanTree &HT, HuffmanCode HC[], int *w, int n) {
// 算法6.13
// w存放n个字符的权值(均>0),构造哈夫曼树HT,
// 并求出n个字符派培猜的哈夫曼编码HC
int i, j
char *cd
int p
int cdlen
if (n<=1) return
m = 2 * n - 1
HT = (HuffmanTree)malloc((m+1) * sizeof(HTNode))// 0号单元未用
for (i=1i<=ni++) { //初始化
HT[i].weight=w[i-1]
HT[i].parent=0
HT[i].lchild=0
HT[i].rchild=0
}
for (i=n+1i<=mi++) { //初始化
HT[i].weight=0
HT[i].parent=0
HT[i].lchild=0
HT[i].rchild=0
}
puts("\n哈夫曼树的构造过程如下所示:")
printf("HT初态:\n 结点 weight parent lchild rchild")
for (i=1i<=mi++)
printf("\n%4d%8d%8d%8d%8d",i,HT[i].weight,
HT[i].parent,HT[i].lchild, HT[i].rchild)
printf(" 按任意键,继续 ...")
getchar()
for (i=n+1i<=mi++) { // 建哈夫曼树
// 在HT[1..i-1]中选择parent为0且weight最小的两个结点中散,
// 其序号分别为s1和s2。
Select(HT, i-1)
HT[s1].parent = iHT[s2].parent = i
HT[i].lchild = s1HT[i].rchild = s2
HT[i].weight = HT[s1].weight + HT[s2].weight
printf("\nselect: s1=%d s2=%d\n", s1, s2)
printf(" 结点 weight parent lchild rchild")
for (j=1j<=ij++)
printf("\n%4d%8d%8d%8d%8d",j,HT[j].weight,
HT[j].parent,HT[j].lchild, HT[j].rchild)
printf(" 按任意键,继续 ...")
getchar()
}
//------无栈非递尘型归遍历哈夫曼树,求哈夫曼编码
cd = (char *)malloc(n*sizeof(char))// 分配求编码的工作空间
p = mcdlen = 0
for (i=1i<=m++i) // 遍历哈夫曼树时用作结点状态标志
HT[i].weight = 0
while (p) {
if (HT[p].weight==0) { // 向左
HT[p].weight = 1
if (HT[p].lchild != 0) { p = HT[p].lchildcd[cdlen++] ='0'}
else if (HT[p].rchild == 0) { // 登记叶子结点的字符的编码
HC[p] = (char *)malloc((cdlen+1) * sizeof(char))
cd[cdlen] ='\0'strcpy(HC[p], cd)// 复制编码(串)
}
} else if (HT[p].weight==1) { // 向右
HT[p].weight = 2
if (HT[p].rchild != 0) { p = HT[p].rchildcd[cdlen++] ='1'}
} else { // HT[p].weight==2,退回退到父结点,编码长度减1
HT[p].weight = 0p = HT[p].parent--cdlen
}
}
} // HuffmanCoding
void main() {
HuffmanTree HTHuffmanCode *HCint *w,n,i
puts("输入结点数:")
scanf("%d",&n)
HC = (HuffmanCode *)malloc(n*sizeof(HuffmanCode))
w = (int *)malloc(n*sizeof(int))
printf("输入%d个结点的权值\n",n)
for(i = 0i <ni++)
scanf("%d",&w[i])
HuffmanCoding(HT,HC,w,n)
puts("\n各结点的哈夫曼编码:")
for(i = 1i <= ni++)
printf("%2d(%4d):%s\n",i,w[i-1],HC[i])
getchar()
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)