数据结构——分别通过数组和队列实现哈夫曼树的构建以及哈夫曼编码的实现(C语言)...

#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;  
}

运行结果:

ce3a5f2d1125a6a9acebda1fdcce2aa78fa.jpg

转载于:https://my.oschina.net/1024and1314/blog/3089660

#include #include #include #include using namespace std; # define MaxN 100//初始设定的最大结点数 # define MaxC 1000//最大编码长度 # define ImpossibleWeight 10000//结点不可能达到的权值 # define n 26//字符集的个数 //-----------哈夫曼的结点结构类型定义----------- typedef struct //定义哈夫曼各结点 { int weight;//权值 int parent;//双亲结点下标 int lchild;//左孩子结点下标 int rchild;//右孩子结点下标 }HTNode,*HuffmanTree;//动态分配数组存储哈夫曼 typedef char**HuffmanCode;//动态分配数组存储哈夫曼编码表 //-------全局变量-------- HuffmanTree HT; HuffmanCode HC; int *w;//权值数组 //const int n=26;//字符集的个数 char *info;//字符值数组 int flag=0;//初始化标记 //********************************************************************** //初始化函数 //函数功能: 从终端读入字符集大小n , 以及n个字符n个权值,建立哈夫曼,并将它存于文件hfmTree中 //函数参数: //向量HT的前n个分量表示叶子结点,最后一个分量表示根结点,各字符的编码长度不等,所以按实际长度动态分配空间 void Select(HuffmanTree t,int i,int &s1,int &s2) { //s1为最小的两个值中序号最小的那个 int j; int k=ImpossibleWeight;//k的初值为不可能达到的最大权值 for(j=1;j<=i;j++) { if(t[j].weight<k&&t[j].parent==0) {k=t[j].weight; s1=j;} } t[s1].parent=1; k=ImpossibleWeight; for(j=1;j<=i;j++) { if(t[j].weight0),构造哈夫曼HT,并求出n个字符的哈弗曼编码HC { int i,m,c,s1,s2,start,f; HuffmanTree p; char* cd; if(num<=1) return; m=2*num-1;//m为结点数,一棵有n个叶子结点的哈夫曼共有2n-1个结点,可以存储在一个大小为2n-1的一维数组HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//0号单元未用 //--------初始化哈弗曼------- for(p=HT+1,i=1;iweight=*w; p->parent=0; p->lchild=0; p->rchild=0; } for(i=num+1;iweight=0; p->parent=0; p->lchild=0; p->rchild=0; } //--------建哈夫曼------------- for(i=num+1;i<=m;i++) { Select(HT,i-1,s1,s2);//在HT[1...i-1]选择parent0weight最小的两个结点,其序号分别为s1s2 HT[s1].parent=i; HT[s2].parent=i; HT[i].lchild=s1; HT[i].rchild=s2;//左孩子权值小,右孩子权值大 HT[i].weight=HT[s1].weight+HT[s2].weight; } //-------从叶子到根逆向求每个字符的哈弗曼编码-------- HC=(HuffmanCode)malloc((num+1)*sizeof(char *));//指针数组:分配n个字符编码的头指针向量 cd=(char*)malloc(n*sizeof(char*));//分配求编码的工作空间 cd[n-1]='\0';//编码结束符 for(i=1;i<=n;i++)//逐个字符求哈弗曼编码 { start=n-1;//编码结束符位置 for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)//从叶子到跟逆向求哈弗曼编码 if(HT[f].lchild==c) cd[--start]='0';//判断是左孩子还是右孩子(左为0右为1) else cd[--start]='1'; HC[i]=(char*)malloc((num-start)*sizeof(char*));//按所需长度分配空间 int j,h; strcpy(HC[i],&cd[start]); } free(cd); } //****************初始化函数****************** void Initialization() { flag=1;//标记为已初始化 int i; w=(int*)malloc(n*sizeof(int));//为26个字符权值分配空间 info=(char*)malloc(n*sizeof(char));//为26个字符分配空间 ifstream infile("ABC.txt",ios::in); if(!infile) { cerr<<"打开失败"<<endl; exit(1); } for(i=0;i>info[i]; infile>>w[i]; } infile.close(); cout<<"读入字符成功!"<<endl; HuffmanCoding(HT,HC,w,n); //------------打印编码----------- cout<<"依次显示各个字符的值,权值或频度,编码如下"<<endl; cout<<"字符"<<setw(6)<<"权值"<<setw(11)<<"编码"<<endl; for(i=0;i<n;i++) { cout<<setw(3)<<info[i]; cout<<setw(6)<<w[i]<<setw(12)<<HC[i+1]<<endl; } //---------将建好的哈夫曼写入文件------------ cout<<"下面将哈夫曼写入文件"<<endl; ofstream outfile("hfmTree.txt",ios::out); if(!outfile) { cerr<<"打开失败"<<endl; exit(1); } for(i=0;i<n;i++,w++) { outfile<<info[i]<<" "; outfile<<w[i]<<" "; outfile<<HC[i+1]<<" "; } outfile.close(); cout<<"已经将字符对应的权值,编码写入根目录下文件hfmTree.txt"<<endl; } //*****************输入待编码字符函数************************* void Input() { char string[100]; ofstream outfile("ToBeTran.txt",ios::out); if(!outfile) { cerr<<"打开失败"<<endl; exit(1); } cout<<"请输入你想要编码的字符串(字符个数应小于100),以#结束"<>string; for(int i=0;string[i]!='\0';i++) { if(string[i]=='\0') break; outfile<<string[i]; } cout<<"获取报文成功"<<endl; outfile.close(); cout<<"------"<<"已经将报文存入根目录下的ToBeTran.txt文件"<<endl; } //******************编码函数**************** void Encoding() { int i,j; char*string; string=(char*)malloc(MaxN*sizeof(char)); cout<<"下面对根目录下的ToBeTran.txt文件中的字符进行编码"<<endl; ifstream infile("ToBeTran.txt",ios::in); if(!infile) { cerr<<"打开失败"<<endl; exit(1); } for(i=0;i>string[i]; } for(i=0;i<100;i++) if(string[i]!='#') cout<<string[i]; else break; infile.close(); ofstream outfile("CodeFile.txt",ios::out); if(!outfile) { cerr<<"打开失败"<<endl; exit(1); } for(i=0;string[i]!='#';i++) { for(j=0;j<n;j++) { if(string[i]==info[j]) outfile<<HC[j+1]; } } outfile<<'#'; outfile.close(); free(string); cout<<"编码完成------"; cout<<"编码已写入根目录下的文件CodeFile.txt中"<<endl; } //******************译码函数**************** void Decoding() { int j=0,i; char *code; code=(char*)malloc(MaxC*sizeof(char)); char*string; string=(char*)malloc(MaxN*sizeof(char)); cout<<"下面对根目录下的CodeFile.txt文件中的代码进行译码"<<endl; ifstream infile("CodeFile.txt",ios::in); if(!infile) { cerr<<"打开失败"<<endl; exit(1); } for( i=0;i>code[i]; if(code[i]!='#') { cout<<code[i]; } else break; } infile.close(); int m=2*n-1; for(i=0;code[i-1]!='#';i++) { if(HT[m].lchild==0) { string[j]=info[m-1]; j++; m=2*n-1; i--; } else if(code[i]=='1') m=HT[m].rchild; else if(code[i]=='0') m=HT[m].lchild; } string[j]='#'; ofstream outfile("TextFile.txt",ios::out); if(!outfile) { cerr<<"打开失败"<<endl; exit(1); } cout<<"的译码为------"<<endl; for( i=0;string[i]!='#';i++) { outfile<<string[i]; cout<<string[i]; } outfile<<'#'; outfile.close(); cout<<"------译码完成------"<<endl; cout<<"译码结果已写入根目录下的文件TextFile.txt中"<<endl; free(code); free(string); } //*************打印编码函数**************** void Code_printing() { int i; char *code; code=(char*)malloc(MaxC*sizeof(char)); cout<<"下面打印根目录下文件CodeFile.txt中的编码"<<endl; ifstream infile("CodeFile.txt",ios::in); if(!infile) { cerr<<"打开失败"<<endl; exit(1); } for( i=0;i>code[i]; if(code[i]!='#') cout<<code[i]; else break; } infile.close(); cout<<endl; ofstream outfile("CodePrin.txt",ios::out); if(!outfile) { cerr<<"打开失败"<<endl; exit(1); } for(i=0;code[i]!='#';i++) { outfile<<code[i]; } outfile.close(); free(code); cout<<"------打印结束------"<<endl; cout<<"该字符形式的编码文件已写入文件CodePrin.txt中"<<endl; } //*************打印哈夫曼函数**************** int numb=0; void coprint(HuffmanTree start,HuffmanTree HT) //start=ht+26这是一个递归算法 { if(start!=HT) { ofstream outfile("TreePrint.txt",ios::out); if(!outfile) { cerr<<"打开失败"<rchild,HT); //递归先序遍历 cout<<setw(5*numb)<weight<rchild==0) cout<<info[start-HT-1]<<endl; outfile<weight; coprint(HT+start->lchild,HT); numb--; outfile.close(); } } void Tree_printing(HuffmanTree HT,int num) { HuffmanTree p; p=HT+2*num-1; //p=HT+26 cout<<"下面打印赫夫曼"<<endl; coprint(p,HT); //p=HT+26 cout<<"打印工作结束"<<endl; } //*************主函数************************** int main() { char choice; do{ cout<<"************哈弗曼编/译码器系统***************"<<endl; cout<<"请选择您所需功能:"<<endl; cout<<":初始化哈弗曼"<<endl; cout<<":输入待编码字符串"<<endl; cout<<":利用已建好的哈夫曼进行编码"<<endl; cout<<":利用已建好的哈夫曼进行译码"<<endl; cout<<":打印代码文件"<<endl; cout<<":打印哈夫曼"<<endl; cout<<":退出"<<endl; if(flag==0) { cout<<"请先初始化哈夫曼,输入I"<<endl; cout<<""<>choice; switch(choice) { case 'I':Initialization();break; case 'W':Input();break; case 'E':Encoding();break; case 'D':Decoding();break; case 'P':Code_printing();break; case 'T':Tree_printing(HT,n);break; case 'Q':;break; default:cout<<"输入的命令出错,请重新输入!"<<endl; } }while(choice!='Q'); free(w); free(info); free(HT); free(HC); system("pause"); return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值