最近拖更了好久,在忙一些琐事,有时间继续加更!
上次实验三二叉树递归与非递归版本已经全部公开,请点击此处。
数据结构实验四要求
题目描述:对任意输入的一段英文,为每个字符编制其相应的哈夫曼编码,并利用该编码为任意输入的0、1序列进行解码。
操作提示:一个完整的系统应具有以下功能:
(1)初始化:从终端读入一段英文字符,统计每个字符出现的频率,建立哈夫曼树,并将该树存入某文件;
(2)编码: 利用建好的哈夫曼树对各字符进行编码,用列表的形式显示在屏幕上,并将编码结果存入另一文件中;
(3)解码: 利用保存的哈夫曼编码,对任意输入的0,1序列能正确解码。
话说我用C语言写的,有好多指针还是挺绕的,虽然思路对的但得不出正确答案,索性使用引用,对指针掌握还是有所欠缺,以后还是好好用C++吧(捂脸ing)。
这次方便同学提供部分主要函数代码(后天代码全部公开)见下:
Tree.h
#ifndef _TREE_H_
#define _TREE_H_
#include <iostream>
#include <string>
#include <cstring>
#include <map>
#include <fstream>
using namespace std;
map<char,int> str;//全局变量,键值对,对字符计数
const int INFMAX=0x3f3f3f3f;
typedef struct{
char c;
int parent;
int LChild;
int RChild;
int weight;
}HTNode,*huffman;
typedef char ** huffmancode;
#endif
Tree.cpp
#include "Tree.h"
/*从ht树中,范围是1-n,选出最小的2个赋值给s1,s2*/
void Select(huffman ht,int n,int &s1,int &s2){
int min=INFMAX;
for(int i=1;i<=n;i++){
if(ht[i].parent==0&&ht[i].weight<min){
min=ht[i].weight;
s1=i;
}
}
min=INFMAX;
for(int i=1;i<=n;i++){
if(ht[i].parent==0&&ht[i].weight<min&&i!=s1){
min=ht[i].weight;
s2=i;
}
}
}
/*创建huffmantree,注意使用&*/
void CreatHuffmanTree(huffman &ht,int n){
int m=2*n-1;
ht=new HTNode[m+1];//第0号位置不使用
map<char,int>::iterator it=str.begin();
//初始化n个结点的信息
for(int i=1;i<=n&&it!=str.end();++i,++it){
ht[i].c=it->first;
ht[i].parent=0;
ht[i].LChild=0;
ht[i].RChild=0;
ht[i].weight=it->second;
}
for(int i=n+1;i<=m;i++){
ht[i].parent=0;
ht[i].LChild=0;
ht[i].RChild=0;
ht[i].weight=0;
}
for(int i=n+1;i<=m;i++){
int s1,s2;
Select(ht,i-1,s1,s2);
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;
}
}
/*通过huffman树进行解码,左为0,右为1*/
void CreatHuffmanCode(huffman ht,int n,huffmancode &hc){
int m=2*n-1;
hc=new char*[n+1];
char *cd;
cd=new char[n+1];
cd[n-1]='\0';
for(int i=1;i<=n;++i){
int start=n-1;
int c=i;
int f=ht[i].parent;
while(f!=0){
--start;
if(ht[f].LChild==c){
cd[start]='0';
}
else{
cd[start]='1';
}
c=f;
f=ht[f].parent;
}
hc[i]=new char[n-start];
strcpy(hc[i],&cd[start]);
}
delete cd;
}
void Decode(huffman ht,int n,string str){
HTNode p=ht[2*n-1];
for(int i=0;i<str.length();++i){
if(str[i]=='0'){
p=ht[p.LChild];
}else if(str[i]=='1'){
p=ht[p.RChild];
}
if(p.LChild==0&&p.RChild==0){
cout<<p.c;
p=ht[2*n-1];
}
}
}
Main.cpp
/*
Author:Jack Leo
All Rights Reserved
*/
#include "Tree.h"
#include "Tree.cpp"
int main(){
/*读取字符并对出现的字符进行计数加权处理*/
cout<<"请输入一段英文字符(可以输入空格,按Enter结束)"<<endl;
string s;
getline(cin,s);
for(int i=0;i<s.length();i++){
if(str.find(s[i])==str.end()){
str.insert(pair<char,int>(s[i],1));
}
else{
++str[s[i]];
}
}
int n=str.size();
/*创建huffman树并显示创建树的过程*/
huffman ht;
CreatHuffmanTree(ht,n);
ofstream file;//文件读写操作
file.open("Tree.txt",ios::out);
cout<<"哈夫曼树创建过程:"<<endl<<"注意:空格ASCII码值为32"<<endl<<"序号\t字符\tASCII\t权值(次数)\t父亲结点\t左孩结点\t右孩结点"<<endl;
file<<"哈夫曼树创建过程:"<<endl<<"注意:空格ASCII码值为32"<<endl<<"序号\t字符\tASCII\t权值(次数)\t父亲结点\t左孩结点\t右孩结点"<<endl;
for(int i=1;i<=n;++i){
cout<<i<<"\t"<<ht[i].c<<"\t"<<int(ht[i].c)<<"\t\t"<<ht[i].weight<<"\t\t"<<ht[i].parent<<"\t\t"<<ht[i].LChild<<"\t\t"<<ht[i].RChild<<endl;
file<<i<<"\t"<<ht[i].c<<"\t"<<int(ht[i].c)<<"\t\t"<<ht[i].weight<<"\t\t"<<ht[i].parent<<"\t\t"<<ht[i].LChild<<"\t\t"<<ht[i].RChild<<endl;
}
for(int i=n+1;i<=2*n-1;i++){
cout<<i<<"\t\t\t\t"<<" \t\t"<<ht[i].parent<<"\t\t"<<ht[i].LChild<<"\t\t"<<ht[i].RChild<<endl;
file<<i<<"\t\t\t\t"<<" \t\t"<<ht[i].parent<<"\t\t"<<ht[i].LChild<<"\t\t"<<ht[i].RChild<<endl;
}
cout<<"已将上述过程写入Tree.txt文档"<<endl;
file.close();
/*
Author:Jack Leo
All Rights Reserved
*/
/*对字符进行解码处理*/
huffmancode hc;
ofstream file_code;
file_code.open("Code.txt",ios::out);
CreatHuffmanCode(ht,n,hc);
cout<<"\n字符哈夫曼编码:"<<endl<<"序号\t字符\t权值(次数)\t编码\t"<<endl;
file_code<<"字符哈夫曼编码:"<<endl<<"序号\t字符\t权值(次数)\t编码\t"<<endl;
for(int i=1;i<=n;i++){
cout<<i<<"\t "<<ht[i].c<<"\t "<<ht[i].weight<<"\t "<<hc[i]<<endl;
file_code<<i<<"\t "<<ht[i].c<<"\t "<<ht[i].weight<<"\t "<<hc[i]<<endl;
}
file_code.close();
cout<<"字符编码已写入Code.txt文档"<<endl;
/*哈夫曼译码处理*/
cout<<"\n译码:"<<endl;
cout<<"请输入0,1序列进行译码"<<endl;
string sm;
cin>>sm;
cout<<"上述0,1序列表示的字符串是"<<endl;
Decode(ht,n,sm);
return 0;
}