#include<stdio.h>
#include<stdlib.h>
//哈夫曼树结点结构
typedef struct {
int weight;//结点权重
int parent, left, right;//父结点、左孩子、右孩子在数组中的位置下标
}HTNode,*HuffmanTree;
int test01=0;
int test02 =0;
int *s1 = &test01;
int *s2 = &test02;
typedef char **HuffCode;
//HT数组中存放的哈夫曼树,end表示HT数组中存放结点的最终位置,s1和s2传递的是HT数组中权重值最小的两个结点在数组中的位置
void Select(HuffmanTree HT,int end)
{
int min1=-1, min2=-1;
//遍历数组初始下标为 1
int min = 1000;
int i;
//找到还没构建树的结点中权重最小的下标
for(i =1; i < end; i++){
if(HT[i].parent ==0 && min > HT[i].weight){
min = HT[i].weight;
min1 = i;
}
}
if(min1== -1) return;
HT[min1].parent =1;
min = 1000;
for(i =1; i < end; i++){
if(HT[i].parent ==0 && min > HT[i].weight){
min = HT[i].weight;
min2 = i;
}
}
HT[min2].parent =1;
if(min1== -1) return;
*s1 = min1;
*s2 = min2;
}
//HT为地址传递的存储哈夫曼树的数组,w为存储结点权重值的数组,n为结点个数
void CreateHuffmanTree(HuffmanTree *HT, int *w, int n)
{
int m,i;
if(n<=1) return; // 如果只有一个编码就相当于0
m= 2*n-1; // 哈夫曼树总节点数,n就是叶子结点
*HT = (HuffmanTree) malloc((m+1)*sizeof(HTNode)); // 0号位置不用
// 初始化哈夫曼树中的所有结点
for(i = 1; i <= n;i++)
{
(*HT)[i].weight = *(w+i-1);
(*HT)[i].parent = 0;
(*HT)[i].left = 0;
(*HT)[i].right = 0;
}
//从树组的下标 n+1 开始初始化哈夫曼树中除叶子结点外的结点
for(i = n+1; i <= m; i++)
{
(*HT)[i].weight = 0;
(*HT)[i].parent = 0;
(*HT)[i].left = 0;
(*HT)[i].right = 0;
}
//构建哈夫曼树
for(i = n+1; i<=m; i++){
Select(*HT,i);
(*HT)[i].left = *s1;
(*HT)[i].right = *s2;
(*HT)[*s1].parent = (*HT)[*s2].parent=i;
(*HT)[i].weight = (*HT)[*s1].weight + (*HT)[*s2].weight;
}
}
//哈夫曼编码(从底部向上)
void haFuCode(HuffmanTree *HT,HuffCode *HC,int n){
int i,start,currentIndex,parentIndex;
char *cd;
//定义一位字符串
cd = (char *)malloc(sizeof(char)*n);
cd[n-1] = '\0';//字符串结束符
*HC = (HuffCode)malloc(sizeof(char *)*(n+1));
for(i = 1; i <=n; i++){
start = n-1;
currentIndex = i;
parentIndex = (*HT+i)->parent;
while(parentIndex !=0){
if((*HT+parentIndex)->left == currentIndex){
cd[--start] ='0';
}else if((*HT+parentIndex)->right == currentIndex){
cd[--start] ='1';
}
//父节点作为孩子节点,继续遍历
currentIndex = parentIndex;
parentIndex= (*HT+parentIndex)->parent;
}
//将该节点的编码保存
(*HC)[i] = (char *)malloc((n-start)*sizeof(char));
strcpy((*HC)[i],&cd[start]);
}
free(cd);
}
//哈夫编码(从顶到底部)
void haFuCode02(HuffmanTree *HT,HuffCode *HC,int n){
int i;
int m = 2*n -1; //节点总数,哈夫曼树是先满二叉树,节点关系:N0 = N2+1
int p = m; //未遍历的节点个数
int index=0;
char *cd = (char *)malloc(sizeof(char)*n);
*HC = (HuffCode)malloc(sizeof(char *)*(n+1));
//初始化节点,权重为遍历次数
for(i = 1; i <= p; i++){
(*HT+i)->weight = 0;
}
while(p != 0){
if((*HT+p)->weight == 0){
(*HT+p)->weight =1;
if((*HT+p)->left != 0){
cd[index++] = '0';
p = (*HT+p)->left;
}
else if((*HT+p)->right == 0){ //左右节点都遍历完,保存编码
(*HC)[p] = (char *)malloc(sizeof(char)*(index+1));
cd[index] = '\0'; //字符串结束符
strcpy((*HC)[p] ,cd); //内置函数
}
}
else if((*HT+p)->weight == 1){ //从左节点返回,再次回到父节点
(*HT+p)->weight =2;
if((*HT+p)->right != 0){
cd[index++] = '1';
p = (*HT+p)->right;
}
}
else if((*HT+p)->weight == 2){ //左右节点都遍历完,返回父节点
(*HT+p)->weight =0;
p = (*HT+p)->parent; //返回父节点
index--;
}
}
}
//打印编码
void PrintHuffmanCode(HuffCode htable,int *w,int n)
{
int i;
printf("Huffman code : \n");
for( i = 1; i <= n; i++){
printf("%d code = %s\n",w[i-1], htable[i]);
}
}
//打印哈夫曼树的数组
void printTreeArr(HuffmanTree *HT,int n){
int i=1;
while( i<=2*n-1){
printf("%d ",(*HT)[i].weight);
i++;
}
printf("\n");
}
int main(void)
{
int w[5] = {2, 8, 7, 6, 5};
int n = 5;
HuffmanTree htree;
HuffCode htable;
HuffCode htable02;
//创造哈夫曼树
CreateHuffmanTree(&htree, w, n);
printTreeArr(&htree,n);
//从低到顶
haFuCode(&htree,&htable,n);
PrintHuffmanCode(htable,w,n);
//从顶部到底部
haFuCode02(&htree,&htable02,n);
PrintHuffmanCode(htable02,w,n);
return 0;
}
队列实现
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//定义哈夫树的节点的结构
typedef struct HafuNode{
int weight;
struct HafuNode* parent;
struct HafuNode* left;
struct HafuNode* right;
}HaNode,*HaTreeNode;
//全局变量,都可以操作
int n= 5;
int test01=0;
int test02 =0;
int *min = &test01;
int *max = &test02;
//二位数组,存放哈夫曼编码
typedef char **HuffCode;
int codeindex = 0;
void swap(int *a, int *b){
int temp;
temp = *a;
*a = *b;
*b = temp;
}
void initArr(HaTreeNode arr,int *w,int *flag){
int i;
for(i = 0; i < 5; i++){
arr[i].weight = w[i];
arr[i].left = NULL;
arr[i].right = NULL;
arr[i].parent = NULL;
}
}
//往动态数组里加入元素
void addNode(HaTreeNode arr,int *flag,int weight,HaTreeNode left,HaTreeNode right){
arr[n].weight = weight;
arr[n].left = left;
arr[n].right = right;
arr[n].parent = NULL;
flag[n] =0;
n++;
}
//找出权重数组的最小的两个权重值的下标
void lookMinIndex(HaTreeNode arr,int *flag){
int i;
int k=-1,kk =-1;
int minWeight01 =100,minWeight02 =100;
for(i = 0; i < n; i++){
if(flag[i] ==0 && minWeight01 > arr[i].weight){
minWeight01 = arr[i].weight;
k = i;
}
}
flag[k] = 1;
for(i = 0; i < n; i++){
if(flag[i] ==0 && minWeight02 > arr[i].weight){
minWeight02 = arr[i].weight;
kk = i;
}
}
flag[kk] = 1;
*min = k;
*max = kk;
}
//构造哈夫曼树,从底部往顶部构造
void create_HafuTree(HaTreeNode* H,HaTreeNode arr,int *flag){
int i;
for(i = 0; i< n; i ++){
//构建哈夫曼树,目标函数就是使树的带权路径长度最小,左右节点可以互换,不影响结果,编码(0/1)没有大小之分
lookMinIndex(arr,flag);
if(*min ==-1|| *max == -1) break;
//将小的放在父节点的右边,大值放在父节点放在左边
(*H) = (HaNode *)malloc(sizeof(HaNode));
//最小值的node
(*H)->left = &arr[*min];
arr[*min].parent = *H ;
(*H)->right = &arr[*max];
arr[*max].parent = *H ;
(*H)->weight =(*H)->left ->weight + (*H)->right ->weight;
addNode(arr,flag, (*H)->weight,(*H)->left,(*H)->right);
}
}
//哈夫曼编码(从底部向上)
void haFuCode(HaTreeNode arr,HuffCode *HC){
int i;
HaTreeNode p;
char *cd;
int start;
HaTreeNode temp;;
cd = (char *)malloc(sizeof(char)*n);
*HC = (HuffCode)malloc(sizeof(char *)*(n+1));
for(i = 0; i <n; i++){
start = n-1; //从叶子节点开始,保存编码,故逆序存放
temp = &arr[i]; //数组当前节点位置
p = arr[i].parent;
while(p != NULL){
if (p->left == temp){
cd[--start] = '0';
}
else if (p->right ==temp){
cd[--start] = '1';
}
temp=p;
printf("%d ",p ->parent->weight);
p= p->parent; //以父节点为孩子节点,继续遍历
}
//将该节点的编码保存
(*HC)[i] = (char *)malloc((n-start)*sizeof(char));
strcpy((*HC)[i],&cd[start]);
}
free(cd);
}
//哈夫曼编码(从上往下) //通过双队列实现
void haFuCodeTopTo(HaTreeNode HT,HaTreeNode arr,HuffCode *HC,int num){
int i;
HaTreeNode p;
HaNode* arrtest[20];
char *cd;
int temp;
int rear = -1,star= -1;
cd = (char *)malloc(sizeof(char)*num);
*HC = (HuffCode)malloc(sizeof(char *)*(num+1));
while(HT != NULL){
while(HT!= NULL){
arrtest[++rear] = HT;
cd[++start] = '0';
HT =HT->left;
++rear;
++start;
}
if (rear != -1){
HT = arrtest[rear--];
if(HT->left ==NULL){
(*HC)[codeindex] = (char *)malloc((n)*sizeof(char));
strcpy((*HC)[codeindex],&cd[start]);
codeindex++;
start--;
}
HT = HT ->right;
cd[start++] = '1';
}
}
free(cd);
}
//打印哈夫曼编码
//打印哈夫曼编码的函数
void PrintHuffmanCode(HuffCode htable,int num){
int i;
printf("Huffman code :\n");
for(i = 0; i < num; i++)
printf(" %s\n",htable[i]);
}
//打印哈夫曼树的原属组
void printf_Test(HaTreeNode arr){
int i;
for(i = 0; i < 9; i++){
if(arr[i].parent == NULL) break;
printf("weight=%d p = %p parentW = %d parentIndex =%p",arr[i].weight,&arr[i], arr[i].parent->weight, arr[i].parent);
printf("\n");
}
printf("\n");
}
//中序遍历
void mid_Search(HaTreeNode Ha){
if(Ha){
mid_Search(Ha->left);
printf("%d Ha = %p \n",Ha ->weight,Ha);
mid_Search(Ha->right);
}
}
int main(){
HaTreeNode Ha;
HuffCode HC;
//节点weight值的数组
int w[5] = {2, 8, 7, 6, 5};
int flag[5] ={0,0,0,0,0};
//创建一个存HaNode的数组
HaNode* arr[11];
//初始化
initArr(arr,w,flag);
create_HafuTree(&Ha,arr,flag);
printf_Test(arr);
mid_Search(Ha);
//哈弗编码
haFuCode(arr,&HC);
PrintHuffmanCode(arr,HC,5);
printf("\n");
return 0;
}
运行结果: