// Question.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "stdio.h"
#include "stdlib.h"
#define StringSize 30//输入最大字符串的大小
struct BiTreeNode//构造二叉树结构体
{
char sign;//二叉树结点符号
int power;//二叉树结点的权值
int path;//哈弗曼编码的路径值
struct BiTreeNode* L;//左指针
struct BiTreeNode* R;//右指针
};
struct CodeStack//顺序栈用来存哈弗曼编码
{
int path[StringSize];
int top;//栈顶指针;
};
void Push(CodeStack *&code, int path)//入栈,存入哈夫曼代码,path为哈弗曼编码值
{
code->top++;
code->path[code->top] = path;
}
void HuffmanCode(BiTreeNode *p, CodeStack *code)//p为每一个节点,code是一个栈,用来存哈弗曼编码
{
if (p != NULL)
{
if (p->path == 0 || p->path == 1)//如果为0或1就存入code
{
Push(code, p->path);//存储当前位置的path值,即哈夫曼编码元素
p->path = code->top;//用path储存当前层数,用来之后再次访问调用(弹栈)
}
if (p->sign != '#')//读到了叶子结点
{
printf("字母:%c 权重:%02d 编码为:", p->sign, p->power);
for (int x = 0; x <= code->top; x++)//从栈底开始输出哈弗曼编码
{
printf("%d", code->path[x]);
}
putchar('\n');//换行准备输出下一组哈弗曼编码
}
HuffmanCode(p->L, code);//左子树深度搜索
code->top = p->path;//这里为访问头结点的位置,当做再次访问此结点。
//将top重置为当前层数(path储存的当前层数)
HuffmanCode(p->R, code);//右子树递归
}
}
void RenewArray(char a[], int address)//删除相同字符,重新生成字符串
{
while (a[address + 1] != '\0')//address之后的元素位置全部向前移动一位
//即删除address位置的元素
{
a[address] = a[address + 1];
address++;
}
a[address] = '\0';//最后一项为空,使得Size减小1
}
void SortArray(BiTreeNode *data[], int k)//哈夫曼数组根据权值大小排序
{
int i, j;
BiTreeNode *x;
for (i = 0; i < k; i++)
for (j = 0; j < k; j++)
if (data[i]->power < data[j]->power)
{
x = data[i];
data[i] = data[j];
data[j] = x;
}
}
void DeleteArray(BiTreeNode *data[], int* boundary)//删除数组中最小的两个元素
{
int i = 0;
while (data[i]->power != 0)//保证数据元素处理干净,多进行两次
{
data[i] = data[i + 2];
i++;
}
*boundary = i - 2;//实际上多了一个,用来存放新构成的树
}
void InitiateStack(CodeStack *&code)//初始化栈
{
code = new CodeStack;
code->top = -1;
}
void CountPower(char store[], BiTreeNode *data[], int* boundary)//统计字符串中各字符的权值
//data为最终要获取的原始数组
{
int i = 0, j = 0, k = 0;//i用来遍历字符串,j用来统计权值, k用来录入哈夫曼数组
char flag;//flag存储要遍历寻找的对象
while (store[0] != '\0')
{
flag = store[0];
for (i = 0; store[i] != '\0';)
{
if (store[i] == flag)
{
RenewArray(store, i);//如果找到相同的字符
//数组从该位置开始全部前移一位并继续从该位置遍历
j++;
}
else//如果不相等便搜索下一个位置
i++;
}
data[k]->sign = flag;
data[k]->power = j;
k++;//指向哈夫曼数组的下一个单元
j = 0;//权值归零用来统计下一个字符的权值
}
*boundary = k;
}
void InitiateStruct(BiTreeNode *data[])//初始化哈夫曼原始数组
{
for (int i = 0; i < StringSize; i++)
{
data[i] = new BiTreeNode;
data[i]->power = 0;
data[i]->L = NULL;
data[i]->R = NULL;
}
}
void InitiateTree(BiTreeNode *data[], BiTreeNode **s, int* boundary)
{
SortArray(data, *boundary);//数组按权值由小到大排序
while (*boundary > 0)//每合成一个数就会删除两个小树
//并在数组中添加新的一棵树
//如此重复直到数组中只有一个元素
{
*s = new BiTreeNode;//生成新的头结点
if (data[0]->power <= data[1]->power)//数组元素权值小的在左边并初始化哈弗曼编码
//如果有相等的则未合并的优先
{
data[0]->path = 0;
data[1]->path = 1;
(*s)->L = data[0];
(*s)->R = data[1];
}
else
{
data[0]->path = 1;
data[1]->path = 0;
(*s)->L = data[1];
(*s)->R = data[0];
}
(*s)->power = data[0]->power + data[1]->power;//头结点的权值是两个子树权值之和
(*s)->sign = '#';//头结点的符号为“#”
(*s)->path = -1;//根结点的路径默认为-1
DeleteArray(data, boundary);//删除数组中最小的两个元素
data[*boundary] = (*s);//数组末尾存放新生成的树
if (*boundary < 0)//如果只剩下一棵树就不用排序
break;
else
SortArray(data, *boundary + 1);//哈夫曼数组根据权值大小排序
}
}
void OperateMode(char store[], BiTreeNode *data[], int *boundary)
{
int flag;
int i=0,j;
char c;
printf("请选择输入模式:1 输入字符串;2 输入字符及其权值:");
scanf("%d",&flag);
system("cls");
switch (flag)
{
case 1:
{
printf("请输入字符串");
scanf("%s", store);//输入字符串
CountPower(store, data, boundary);//统计字符串中各字符的权值存入data中
system("cls");
break;
}
case 2:
{
printf("当输入的符号为“#”时退出输入\n");
while (1)
{
printf("请输入符号:");
getchar();
scanf("%c",&c);
if (c == '#')
break;
else
data[i]->sign = c;
printf("请输入权重(正整数,等比例缩放):");
scanf("%d",&j);
data[i]->power = j;
i++;
}
*boundary = i;
system("cls");
break;
}
}
}
void main()
{
int boundary = 0;//boundary记录原始数据的个数
char store[StringSize];//用来存入原始字符串
BiTreeNode *data[StringSize];//用来存储哈夫曼树的原始数据
BiTreeNode *head;//head用来作树的根
CodeStack *code;//记录哈弗曼编码
InitiateStack(code);//初始化哈弗曼编码
InitiateStruct(data);//初始化最小二叉树
OperateMode(store, data, &boundary);//模式选择
InitiateTree(data, &head, &boundary);//构建哈夫曼树
HuffmanCode(head, code);//输出哈弗曼编码
getchar();
getchar();
}
哈夫曼编码的实现
最新推荐文章于 2022-06-25 17:22:01 发布
418

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



