数据结构课设-哈夫曼树

1、建立哈夫曼树:读入文件(*.souce),统计文件中字符出现的频度,并以这些字符的频度作为权值,建立哈夫曼树。

2、编码:利用已建立好的哈夫曼树,获得各个字符的哈夫曼编码,并对正文进行编码,然后输出编码结果,并存入文件(*.code)中。

3、译码:利用已建立好的哈夫曼树将文件(*.code)中的代码进行译码,并输出译码结果,并存入文件(*.decode)中。

4、利用位操作,实现文件的压缩与解压。(选作)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 100
#define M 2*N-1 
#define MAXINT 32767
#define ch 30
#define NUM 100
typedef char numcode;
typedef char charcode;
typedef char* HuffmanCode[N] ;
typedef struct{
	char data;//字符 
    int weight;//权值 
    int parent; 
    int lchild;
    int rchild; //父结点及左右孩子结点 
}HTNode,HuffmanTree[M]; 

void CrtHuffmanTree(HuffmanTree ht,int w[],int n);
void select(HuffmanTree ht,int pos,int *s1,int *s2);

void CrtHuffmanTree(HuffmanTree ht,int w[],int n)//创建哈夫曼树 
{
    int i,s1,s2,m;
    m=2*n-1;
    for(i=0;i<n;i++){
        ht[i].weight=w[i];ht[i].parent=-1;
        ht[i].lchild=-1;ht[i].rchild=-1;
    }
    for(i=n;i<m;i++){
        ht[i].weight=0;ht[i].parent=-1;
        ht[i].lchild=-1;ht[i].rchild=-1;
    }
    for(i=n;i<m;i++) {
        select(ht,i-1,&s1,&s2);
        ht[i].weight=ht[s1].weight+ht[s2].weight;
        ht[s1].parent=i;
        ht[s2].parent=i;
        ht[i].lchild=s1;
        ht[i].rchild=s2;
    }
}
void select(HuffmanTree ht,int pos,int *s1,int *s2)
{
    int i,j,m1,m2;
    m1=m2=MAXINT;
    for(j=0;j<=pos;j++) {
        if(ht[j].weight<m1&&ht[j].parent==-1){
            m2=m1;*s2=*s1;
            *s1=j;m1=ht[j].weight;
        }
        else if(ht[j].weight<m2&&ht[j].parent==-1){
            m2=ht[j].weight;
            *s2=j;
        }
    }
}
void CrtHuffmanCode(HuffmanTree ht,HuffmanCode hc,int n){
    char *cd;int start,c,p,i;
    cd=(char*)malloc(n*sizeof(char));
    cd[n-1]='\0';   
    for(i=0;i<n;i++){
        start=n-1;c=i;
        p=ht[i].parent;
        while(p!=-1){
            --start;
            if(ht[p].lchild==c) cd[start]='0';
            else    cd[start]='1';
            c=p;p=ht[p].parent;
        }
        hc[i]=(char*)malloc((n-start)*sizeof(char));        
        strcpy(hc[i],&cd[start]);
    }
    free(cd);
}

void printcode(char s[],HuffmanCode hc,int length)//打印输出各字符 
{
    int i; 
    for( i=0;i<length;i++){
        printf("\t\t\t\t%c:",s[i]);
        printf("%s\n",hc[i]);

    }
}
void chartocode(charcode c[],char s[],HuffmanCode hc,int length){ 
	printf("\n");
    int i=0;
    int j;
    FILE *fp;
	if((fp=fopen("编码后文件.txt","wt"))==NULL)
	{
		printf("写文件出错!!按任意键退出。");
		getch();	
		exit(0);	
	}
    while(c[i]!='\0'){    
        for(j=0;j<length;j++){
            if(c[i]==s[j])
            {
                printf("%s",hc[j]);
                fprintf(fp,"%s",hc[j]) ;//向所建文件写一字符串  
			//	printf("%s",hc[j]);
			//	printf("保存成功!!请按任意键继续。\n");
            }
        }
        i++;
    }
    printf("\n");  
	fclose(fp);
	//printf("按任意键返回主菜单!!!");
    //getch();
}
void  numtochar(numcode ns[],HuffmanTree ht,char s[],int length) 
{
	printf("\n");
	  FILE *fp;
	if((fp=fopen("译码后文件.txt","wt"))==NULL)
	{
		printf("写文件出错!!按任意键退出。");
		getch();	
		exit(0);	
	}
	int m; 
	int i=0;
	int key;
	HTNode g;
    m=2*length-1; 
    while(ns[i]!='\0'){
        g=ht[m-1];     
        while(g.lchild!=-1){
            switch(ns[i]){              
            case '0':key=g.lchild;g=ht[g.lchild];break;
            case '1':key=g.rchild;g=ht[g.rchild];break;
            }
            i++;
        }
         printf("%c",s[key]);
         fprintf(fp,"%c",s[key]) ;//向所建文件写一字符串 
         
    }
    	fclose(fp);
}
void print1()
{
	int i;
	system("cls");
	printf("\n\n");
	printf("\t\t|******************************|\n");
	printf("\t\t||****************************||\n");
	printf("\t\t|||                          |||\n");
	printf("\t\t|||   欢迎进入ZERO编码系统   |||\n");
	printf("\t\t|||                          |||\n");
	printf("\t\t||****************************||\n");
	printf("\t\t|******************************|\n");
	printf("\n\t\t\t系统开始启动.........\n");
  	printf("============================================================================\r");
	for(i=1;i<77;i++) 
  {
   Sleep(40);
   printf(">");
	}
}
void print2()
{
	system("cls");
	printf("\n\n\n\n");
	printf("\t\t\t|******************************|\n");
	printf("\t\t\t||****************************||\n");
	printf("\t\t\t|||                          |||\n");
	printf("\t\t\t|||        谢谢使用          |||\n");
	printf("\t\t\t|||                          |||\n");
	printf("\t\t\t||****************************||\n");
	printf("\t\t\t|******************************|\n");
	Sleep(2000);
}
void print3()
{
		system("cls");
	printf("\t\t\t|*******************************|\n");
	printf("\t\t\t|       欢迎来到ZERO编码世界    |\n");
	printf("\t\t\t|*******************************|\n");
	printf("\t\t\t|        1.初始化源文件         |\n");
	printf("\t\t\t|        2.查询字符的编码       |\n");
	printf("\t\t\t|        3.查询编码后的文件     |\n");
	printf("\t\t\t|        4.查询译码后的文件     |\n");
	printf("\t\t\t|-------------------------------|\n");
	printf("\t\t\t|-------------------------------|\n");
	printf("\t\t\t|         0.退出程序            |\n");
	printf("\t\t\t|===============================|\n");
}
void save_in_f1()//创建文件
{
	char ch1[100];
	FILE *fp;
	if((fp=fopen("源文件.txt","wt"))==NULL)
	{
		printf("写文件出错!!按任意键退出。");
		getch();	
		exit(0);	
	}
	printf("请输入原始文档:\n");
    scanf("%s",ch1);
	fprintf(fp,"%s",ch1) ;//向所建文件写一字符串  
	printf("%s",ch1);
	printf("保存成功!!请按任意键继续。\n");
	fclose(fp);
	printf("按任意键返回主菜单!!!");
    getch();
} 
int main(){
	print1();
    HuffmanTree ht;
	HuffmanCode hc;
	charcode c[1000];
	numcode ns[1000];
    int i;
    int n;
	int j,k;
	int loop;
	int count[95]={0};    //计数数组初始化
	int w[N]={0};
    int num=0; 
    int length;
	int choice;
	int back;
	char s[1000]={0}; 
    char b[1000]={0};       //*a[10]定义了一个指针数组	
	FILE *fp;
	loop1:
	if((fp=fopen("e:\\数据结构实验报告\\源文件.txt", "rw"))==NULL)
		printf("读取失败!");
	else  
	{
		i=0;
		while(!feof(fp)) 
		{
			b[i]=fgetc(fp);
			i++;
		//	printf("%d\t",i);
		}
//	printf("\nb:%s",b);
//	system("pause");
	}
	length=i;
//	printf("length:%d\n",length);
 	for( j=0;j<length;j++)
 	{
  		++count[b[j]-32];      //统计每种字符的个数
  	//	printf("%c的权值:%d",b[j],count[b[j]-33]);
  	}
  	for(k=0,j=0;k<95;k++)
   		if(count[k])
  		{
   			w[j]=count[k];
   			s[j]=k+32;
   	//		printf("%c:%d\n",s[j],w[j]);
   			j++;
   		}
	length=j;
//	printf("length:%d",length);
//	system("pause");
    CrtHuffmanTree(ht,w,length);
    CrtHuffmanCode(ht,hc,length);
    loop:
    	{
   	print3();
    scanf("%d",&choice); 
    switch(choice)
	{
		case 1:{
			    system("cls");
			    save_in_f1();
			    CrtHuffmanTree(ht,w,length);
    		    CrtHuffmanCode(ht,hc,length);
    		    printf("返回上一层(1/0)"); 
   				scanf("%d",&back); 
   					if(back==1)
   						goto loop1;
   					print2();
				break;
			}
		case 2:system("cls");
				printcode(s,hc,length);
				printf("返回上一层(1/0)"); 
   				scanf("%d",&back); 
   					if(back==1)
   						goto loop;
   					print2();
				break;//对的 
		case 3:{
				system("cls");
				FILE *fp;
	 				if((fp=fopen("e:\\数据结构实验报告\\待编码文件.txt", "rw"))==NULL)
							printf("读取失败!");
					else{
						    i=0;
					        while(!feof(fp)) 
							{
								c[i]=fgetc(fp);
								printf("%c",c[i]);
								i++;
							}	
					}
   				chartocode(c,s,hc,i); 
   				printf("返回上一层(1/0)"); 
   				scanf("%d",&back); 
   					if(back==1)
   						goto loop;
   					print2();
				break;
				}
		case 4:	{	system("cls");
					FILE *fp;
	 					if((fp=fopen("e:\\数据结构实验报告\\待译码文件.txt", "rw"))==NULL)
							printf("读取失败!");
						else fscanf(fp,"%s",ns);
					fclose(fp);
				//	printf("\n");
					printf("ns:%s",ns);
					numtochar(ns,ht,s,length);
					printf("\n");
					printf("返回上一层(1/0)"); 
   					scanf("%d",&back); 
   					if(back==1)
   						goto loop;
   					print2(); 
					break;
				}
		case 0:print2();break;
	}
	}
}

设计流程图:

 

  • 10
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
为了回答这个问题,我将介绍哈夫曼树的基本概念和构建过程,以及如何使用哈夫曼树进行编码。 哈夫曼树是一种特殊的二叉树,它的叶子节点对应于要编码的字符,而非叶子节点对应于权值。哈夫曼树的构建过程是这样的: 1. 统计文件中每个字符出现的频度。 2. 将每个字符及其频度作为一个节点,构建一个森林。 3. 从森林中选出两个权值最小的节点,将它们合并成一个新节点,权值为两个节点的权值之和,新节点作为一棵树的根节点,原来的两个节点作为新节点的左右子节点。 4. 将新节点插入到森林中,重复步骤3,直到森林中只剩下一棵树,这棵树就是哈夫曼树哈夫曼树构建完成后,就可以使用它来进行编码了。编码的过程是这样的: 1. 从哈夫曼树的根节点开始,如果当前节点是叶子节点,则输出该节点对应的字符的编码。 2. 如果当前节点不是叶子节点,则根据要编码的字符在哈夫曼树中的位置,向左或向右遍历哈夫曼树,直到找到叶子节点为止。 下面是一个Python实现的例子,假设要编码的文件名为input.txt,编码后的文件名为output.txt: ```python import heapq import os class HuffmanNode: def __init__(self, char, freq): self.char = char self.freq = freq self.left = None self.right = None def __lt__(self, other): return self.freq < other.freq class HuffmanTree: def __init__(self, text): self.text = text self.freq = {} self.heap = [] self.codes = {} self.reverse_codes = {} def count_freq(self): for char in self.text: if char in self.freq: self.freq[char] += 1 else: self.freq[char] = 1 def make_heap(self): for char in self.freq: node = HuffmanNode(char, self.freq[char]) heapq.heappush(self.heap, node) def merge_nodes(self): while len(self.heap) > 1: node1 = heapq.heappop(self.heap) node2 = heapq.heappop(self.heap) merged = HuffmanNode(None, node1.freq + node2.freq) merged.left = node1 merged.right = node2 heapq.heappush(self.heap, merged) def make_codes_helper(self, root, current_code): if root is None: return if root.char is not None: self.codes[root.char] = current_code self.reverse_codes[current_code] = root.char return self.make_codes_helper(root.left, current_code + "0") self.make_codes_helper(root.right, current_code + "1") def make_codes(self): root = heapq.heappop(self.heap) current_code = "" self.make_codes_helper(root, current_code) def get_encoded_text(self): encoded_text = "" for char in self.text: encoded_text += self.codes[char] return encoded_text def pad_encoded_text(self, encoded_text): extra_padding = 8 - len(encoded_text) % 8 for i in range(extra_padding): encoded_text += "0" padded_info = "{0:08b}".format(extra_padding) padded_encoded_text = padded_info + encoded_text return padded_encoded_text def get_byte_array(self, padded_encoded_text): if len(padded_encoded_text) % 8 != 0: print("Encoded text not padded properly") exit(0) b = bytearray() for i in range(0, len(padded_encoded_text), 8): byte = padded_encoded_text[i:i+8] b.append(int(byte, 2)) return b def compress(self): self.count_freq() self.make_heap() self.merge_nodes() self.make_codes() encoded_text = self.get_encoded_text() padded_encoded_text = self.pad_encoded_text(encoded_text) b = self.get_byte_array(padded_encoded_text) with open("output.txt", "wb") as output: output.write(bytes(b)) print("Compressed") return "output.txt" def remove_padding(self, padded_encoded_text): padded_info = padded_encoded_text[:8] extra_padding = int(padded_info, 2) padded_encoded_text = padded_encoded_text[8:] encoded_text = padded_encoded_text[:-1*extra_padding] return encoded_text def decode_text(self, encoded_text): current_code = "" decoded_text = "" for bit in encoded_text: current_code += bit if current_code in self.reverse_codes: char = self.reverse_codes[current_code] decoded_text += char current_code = "" return decoded_text def decompress(self, input_path): with open(input_path, "rb") as file: bit_string = "" byte = file.read(1) while byte: byte = ord(byte) bits = bin(byte)[2:].rjust(8, '0') bit_string += bits byte = file.read(1) encoded_text = self.remove_padding(bit_string) decompressed_text = self.decode_text(encoded_text) with open("decompressed.txt", "w") as output: output.write(decompressed_text) print("Decompressed") return "decompressed.txt" text = open("input.txt", "r").read() tree = HuffmanTree(text) compressed_file_path = tree.compress() decompressed_file_path = tree.decompress(compressed_file_path) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值