#include <iostream.h>
#include <fstream.h>
#include <string.h>
class Data {
public:
char ch;
Data(){
ch = NULL;
}
};
typedef class Huffman {
public:
Data data;
int weight;
int parent, lchild, rchild;
Huffman(){
weight = parent = lchild = rchild = NULL;
}
} * HuffmanTree;
typedef char ** HuffmanCode;
// 在数组中选择两个小的权的数据
void Select(int *tw, int n, int &s1, int &s2)
{
// 建立临时变量temp_w,用来存放最小的weight
int temp_w, i = 1;
while(!tw[i])
{
i++;
}
temp_w = tw[i];
s1 = i;
// 第一遍先确定s1
for(; i<=n; i++)
{
if(temp_w > tw[i])
{
if(tw[i] != NULL)
{
temp_w = tw[i];
s1 = i;
}// ifin
}// if
}//for
i = 1;
while(!tw[i] || i == s1)
{
i++;
}
temp_w = tw[i];
s2 = i;
for(; i<=n; i++)
{
if(i == s1)
goto loop;
if(temp_w > tw[i])
{
if(tw[i])
{
temp_w = tw[i];
s2 = i;
}// ifin
loop:;
}// if
}// for
// 使权小的放到s1
if(tw[s1]>tw[s2])
{
temp_w = s1;
s1 = s2;
s2 = temp_w;
}// if
// 取得两个小的位置后,将备用temp_array_w位置上的权抹去,表示已经被访问
tw[s1] = tw[s2] = NULL;
tw[0] = tw[0]-2;
}
void Initialization (HuffmanTree &HT, HuffmanCode &HC, int n)
{
// 给文件一编码个数的个标记,放在HT[0]行中
HT[0].weight = n;
HT[0].data.ch = 3;
int i;
// 建立一个辅助建立树用的权组
int *temp_array_w = new int[2*n];
// 初始化数组里的权都为0
for(i = 1; i<=2*n -1; i++)
temp_array_w[i] = 0;
for(i = 1; i<=n; i++)
{
cout << "输入字符: ";
cin >> HT[i].data.ch;
if(HT[i].data.ch == '\32')
HT[i].data.ch = '|';
cout << "输入权: ";
cin >> HT[i].weight;
// 把辅助权组赋和权一样的值
temp_array_w[i] = HT[i].weight;
// 用不用的0号单元记录个数
temp_array_w[0] = i;
}// for
// 建立标志s1和s2
int s1, s2;
s1 = s2 = NULL;
// 建立huffman树
for(i = n + 1; i<=2*n - 1; i++)
{
Select(temp_array_w, i-1, s1, s2);
cout << s1 << "//" << s2 << endl;
HT[i].weight = temp_array_w[i] = HT[s1].weight + HT[s2].weight;
HT[i].lchild = s1;
HT[i].rchild = s2;
HT[s1].parent = HT[s2].parent = i;
HT[i].data.ch = '#';
}// for
cout << "\tData\tweight\tparent\tlchild\trchild" << endl;
for(i = 1; i<=2*n - 1; i++)
cout << "\t" << HT[i].data.ch << "\t" << HT[i].weight << "\t" << HT[i].parent << "\t" << HT[i].lchild << "\t" << HT[i].rchild << endl;
// 建立好了树后打印输出到文件humTree中
ofstream HumTreeOut("humTree.dll");
// 把个数记录到文件开始
HumTreeOut << HT[0].weight << endl;
for(i = 1; i<=2*n -1; i++)
{
HumTreeOut << HT[i].data.ch << "\n" << HT[i].weight << "\n" << HT[i].parent << "\n" << HT[i].lchild << "\n" << HT[i].rchild << endl;
}
HumTreeOut.close();
}// void
// 通过树给字符编码,并且把编码输入到CodeFile中
void Encoding (HuffmanCode &HC, HuffmanTree &HT, int n, ifstream &tobetranfile)
{
char *cd = new char[n];
cd[n-1] = '\0';
int i = 1;
for(; i<=n; i++)
{
int start = n -1;
int c, f;
for(c = i, f = HT[i].parent; f!=0; c = f, f = HT[f].parent)
if(HT[f].lchild == c)
cd[--start] = '0';
else
cd[--start] = '1';
HC[i] = new char[n-start];
strcpy(HC[i], &cd[start]);
}
delete cd;
char temp_file_ch;
ofstream CodeOut("CodeFile.txt", ios::ate); // ios::ate表示一个open模式,是在文件后面续写
while(!tobetranfile.eof()) // 一旦文件到了末尾,eof()函数会返回一个非零值
{
tobetranfile.get(temp_file_ch);
for(i = 1; i<=n; i++)
{
if(temp_file_ch == HT[i].data.ch) // 如果相等,便用编码替换
CodeOut << HC[i];
}
}
CodeOut.close();
}
void Decoding (HuffmanTree &HT, ifstream &CodeFile, int n)
{
ofstream TextOut("TextFile.txt", ios::ate);
char temp_code_ch;
int temp_num = 2*n - 1;
while(!CodeFile.eof())
{
CodeFile.get(temp_code_ch);
if(temp_code_ch == '1')
if(!HT[temp_num].rchild)
{
TextOut << HT[temp_num].data.ch;
temp_num = 2*n - 1;
}
else
{
temp_num = HT[temp_num].rchild;
if(!HT[temp_num].rchild) //其实随便一个孩子为空就代表是叶子节点
{
TextOut << HT[temp_num].data.ch;
temp_num = 2*n - 1;
}
}
else
if(!HT[temp_num].lchild)
{
TextOut << HT[temp_num].data.ch;
temp_num = 2*n - 1;
}
else
{
temp_num = HT[temp_num].lchild;
if(!HT[temp_num].lchild) //其实随便一个孩子为空就代表是叶子节点
{
TextOut << HT[temp_num].data.ch;
temp_num = 2*n - 1;
}
}
}
TextOut.close();
cout << "已经翻译到Text.txt文件中" << endl;
}
// 通过已存在的humtree.dll建立新的树
bool CreatNewHum(HuffmanTree &HT, int &n)
{
char *ch_name = new char[30];
// 存放从文件中读取的字符
int temp_n;
char temp_ch;
int i = 1;
cout << "Please Inputing the File name :";
cin >> ch_name;
ifstream HuffmanTreeIn(ch_name);
if(HuffmanTreeIn.fail())
{
HuffmanTreeIn.close();
cout << "不能打开文件" << endl;
return false;
}
// HuffmanTree HT_TEMP = HT;
// HuffmanTreeIn.getline(temp_line, 9);
HuffmanTreeIn >> temp_n; // 一个单词为单位输入
HuffmanTreeIn.get(temp_ch);
// HuffmanTreeIn.seekg(1);
HT = new Huffman[2*temp_n];
// delete HT_TEMP;
// 通过读入文件中的数据给HT赋值
/*
for(;i<20;i++)
{
HuffmanTreeIn.get(temp_ch);
cout << temp_ch;
}
//*/
//*
int j = 1;
while(!HuffmanTreeIn.eof())
{
if(i%5 == 1)
{
HuffmanTreeIn >> HT[j].data.ch;
HuffmanTreeIn.get(temp_ch); // 用于回收回车符号
i++;
}
if(i%5 == 2)
{
HuffmanTreeIn >> HT[j].weight;
HuffmanTreeIn.get(temp_ch);
i++;
}
if(i%5 == 3)
{
HuffmanTreeIn >> HT[j].parent;
HuffmanTreeIn.get(temp_ch);
i++;
}
if(i%5 == 4)
{
HuffmanTreeIn >> HT[j].lchild;
HuffmanTreeIn.get(temp_ch);
i++;
}
if(i%5 == 0)
{
HuffmanTreeIn >> HT[j].rchild;
HuffmanTreeIn.get(temp_ch);
i++;
}
// i自加到5的倍数后j++
if(i%5 == 1)
j++;
// 防止输入最后一个定位符号
if(i > (2*temp_n -1)*5)
break;
}// while
//*/
// 从指定文件里读入树型
HuffmanTreeIn.close();
n = temp_n;
return true;
}
void PrintCode ()
{
char *name_ch = new char[51];
ifstream FileIn("CodeFile.txt");
ofstream FileOut("CodePrin.txt", ios::ate);
if(FileIn.fail())
cout << "文件打开错误!" << endl;
while(!FileIn.eof())
{
FileIn.getline(name_ch, 51);
cout << name_ch << endl;
FileOut << name_ch << endl;
}
FileIn.close();
FileOut.close();
}
void TreePrint ()
{
}
void TitalPrinT() {
cout << "\t=========================================================" << endl;
cout << endl;
cout << "\t=\t\t\tHUFFMANTREE\t\t\t=" << endl;
cout << endl;
cout << "\t=\t\tI:INITIAL A HUFFMAN TREE\t\t=" << endl;
cout << endl;
cout << "\t=\t\tE:ENCODEING THE DATA\t\t\t=" << endl;
cout << endl;
cout << "\t=\t\tD:DECODEING THE DATA\t\t\t=" << endl;
cout << endl;
cout << "\t=\t\tQ:QUIT\t\t\t\t\t=" << endl;
cout << endl;
cout << "\t=========================================================" << endl;
}
// 把几个运算的函数全都放到一个里面去,主函数main就只调用下运算函数
void ComputeHuffman ()
{
// 建立个临时输入存放选项的变量
char temp_input = NULL;
TitalPrinT();
// 记录要给几个编码
int n = 0;
// 先是主体界面 直到按Q才退出
while(temp_input != 'Q')
{
// 建立操作变量
char temp_choise = 0;
HuffmanTree HT;
HuffmanCode HC;
// 用switch/case来判断到底按了哪个选项
cout << "CHOOSE WHICH DO YOU SELECT..." << endl;
cin >> temp_input;
switch(temp_input)
{
case 'I':
cout << "How many numbers need to be initialized: ";
cin >> n;
// 建立数组存放数据
HT = new Huffman[2*n];
Initialization (HT, HC, n);
break;
case 'E':
{
//*
cout << "Inputing the HumffmanTree from the (F)ile or (M)emory : ";
cin >> temp_choise;
switch(temp_choise)
{
case 'F':
if(!CreatNewHum(HT, n))
continue;
break;
case 'M':
// 什么都不做
break;
default:
cout << "Please Pess F or M..." << endl;
continue;
}// switch
//*/
cout << "Translating in (F)ile or (P)ressing: ";
cin >> temp_choise;
switch(temp_choise)
{
case 'F':
break;
case 'P':
{
cout << "由于本人精力限制,现在最多只能输入80个字符" << endl;
char *temp_press_word = new char[81];
cin >> temp_press_word;
// 可以覆盖以前的ToBeTran.txt文件
ofstream CodeFileOut("ToBeTran.txt");
CodeFileOut << temp_press_word;
break;
}
}
HC = new char*[n+1];
ifstream ToBeTranFile("ToBeTran.txt");
Encoding(HC, HT, n, ToBeTranFile);
ToBeTranFile.close();
for(int i = 1; i<=n; i++)
cout << HT[i].data.ch << "<-->" << HC[i] << endl;
}
// 利用建立好的huffman树(如果不在内存则从文件humTree中读入),对文件
// ToBeTran中的正文进行编码,然后将结果寸入CodeFile.txt文件中.
break;
case 'D':
{
// 可以通过不同的树来翻译
cout << "Inputing the HumffmanTree from the (F)ile or (M)emory : ";
cin >> temp_choise;
switch(temp_choise)
{
case 'F':
{
if(!CreatNewHum(HT, n))
continue;
HC = new char*[n+1];
/*
ifstream ToBeTranFile("ToBeTran.txt");
Encoding(HC, HT, n, ToBeTranFile);
ToBeTranFile.close();
*/
}
break;
case 'M':
// 什么都不做
break;
default:
cout << "Please Pess F or M..." << endl;
continue;
}// switch
ifstream CodeFile("CodeFile.txt");
Decoding(HT, CodeFile, n);
CodeFile.close();
}
// 利用建立好的haffman树将文件codefile中的代码进行翻译.结果寸入文件TextFile.txt中
break;
case 'P':
PrintCode();
// 打印代码,50个每行,并且将此字符形式的编码文件写入CodePrin中
break;
case 'T':
// 印huffman树,将已经在内存的huffman树以直观的方式显示,同时将此字符形式的huffman树写
// 入文件TreePrint中
break;
case 'Q':
return;
default:
cout << "Please inputing in \" I E D Q \"..." << endl;
continue;
}// switch
// 回到主菜单
TitalPrinT();
}// while
}// ComputerHuffman
void main()
{
ComputeHuffman();
}
本文地址:http://com.8s8s.com/it/it24189.htm