Huffman编码及数据结构介绍
Huffman编码及数据结构介绍
#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(); }