//*******************************huffman.h********************** //*****************叶子结点为n的哈夫曼树共有2n-1个结点********** #ifndef HUFFMAN_H #define HUFFMAN_H class HuffmanNode { public: char info; //结点信息 double weight; //结点权值 int parent, lchild, rchild; //父亲结点,左右孩子结点 HuffmanNode() { parent=lchild=rchild=-1; } HuffmanNode(const char &data, const double &wt, const int &pa=-1, const int &lch=-1, const int &rch=-1) { info=data; weight=wt; parent=pa; lchild=lch; rchild=rch; } }; //class HuffmanNode end class HuffmanTree { public: HuffmanTree(const int &s=100) { maxSize=(s>100?s:100); arrayTree=new HuffmanNode[maxSize]; currentSize=0; codeArray=0; } ~HuffmanTree() { delete[] arrayTree; if (codeArray!=0) delete[] codeArray; } void run(const char*, const char*, const char*); private: HuffmanNode *arrayTree; //哈夫曼结点数组 int maxSize; //数组最大值 int currentSize; //当前数组大小 void insert(const char&, const double&); //插入结点 void createHuffmanTree(); //创建哈夫曼树 void createHuffmanCode(); //创建哈夫曼编码 int findPosition(const char &) const; //返回字符在arrayTree[]中的位置 int getLongestCodeLength() const; //返回编码系统中长度最大的编码的位置 int isEqual(const char *s) const; //判断s是否存在于编码系统中,若存在则返回s在编码系统中的位置,否则返回-1 void print(); //打印huffman编码 private: class Code { //HuffmanTree的私有类,编码类 public: Code():length(10) { ptr=new char[length]; } ~Code() { delete[] ptr; } char *ptr; const int length; }; Code *codeArray; //数组大小为currentSize void reverse(char arr[]); }; //class HuffmanTree end #endif //huffman.h end //**************************huffman.cpp********************** #include #include //for ofstream ifstream #include //for numeric_limits::max() #include //for exit() #include //for strlen(), strcpy(), strcmp() #include "huffman.h" using namespace std; void HuffmanTree::insert(const char &data, const double &wt) { //插入结点 if (2*currentSize-1 >= maxSize) //叶子结点为n的哈夫曼树共有2n-1个结点 return; arrayTree[currentSize].info=data; arrayTree[currentSize].weight=wt; currentSize++; } void HuffmanTree::reverse(char arr[]) { //反转字符串 const int len=strlen(arr); char *p; p=new char[len+1]; strcpy(p, arr); p[len]='\0'; int k=0; for (int i=len-1; i>=0; i--) arr[i]=p[k++]; arr[len]='\0'; delete[] p; } int HuffmanTree::findPosition(const char &ch) const { //返回字符ch在arrayTree[]中的位置 for (int i=0; i<currentsize; i++) if (arrayTree[i].info == ch) return i; return -1; } int HuffmanTree::getLongestCodeLength() const { //返回编码数组codeArray[]长度最长的编码的位置 if (currentSize == 0) return -1; int len=strlen(codeArray[0].ptr); int i=1; while (i < currentSize) { int tmp=strlen(codeArray[i].ptr); if (tmp > len) len=tmp; i++; } return len; } int HuffmanTree::isEqual(const char *s) const { //判断s的编码是否存在,若存在返回编码在数组codeArray[]中的位置,否则返回-1 for (int i=0; i<currentsize; i++)="" if (strlen(s) == strlen(codeArray[i].ptr)) //可以去掉此行 if (strcmp(s, codeArray[i].ptr) == 0) return i; return -1; } void HuffmanTree::print() { //打印编码 int k=0; while (k < currentSize) { cout<<arraytree[k].info<<'('<<arraytree[k].weight<<"): "<<codearray[k].ptr<<endl; k++; } } void HuffmanTree::createHuffmanTree() { //构造huffmanTree int i=currentSize; int k; double wt1, wt2; int lnode, rnode; while (i < 2*currentSize-1) { wt1=wt2=numeric_limits::max(); k=0; while (k < i) { if (arrayTree[k].parent==-1) { if (arrayTree[k].weight<wt1) { wt2=wt1; rnode=lnode; wt1=arrayTree[k].weight; lnode=k; } else if (arrayTree[k].weight<wt2) { wt2=arrayTree[k].weight; rnode=k; } } k++; } arrayTree[i].weight = arrayTree[lnode].weight+arrayTree[rnode].weight; arrayTree[i].lchild=lnode; arrayTree[i].rchild=rnode; arrayTree[lnode].parent=arrayTree[rnode].parent=i; i++; } } void HuffmanTree::createHuffmanCode() { //构造huffmanCode,即哈夫曼编码 codeArray=new Code[currentSize]; int i=0; int k, n, m; while (i < currentSize) { k = arrayTree[i].parent; n=0; m=i; while (k!=-1 && k<currentsize*2-1) { if (arrayTree[k].lchild==m) codeArray[i].ptr[n++]='0'; else if (arrayTree[k].rchild==m) codeArray[i].ptr[n++]='1'; m=k; k=arrayTree[m].parent; } codeArray[i].ptr[n]='\0'; reverse(codeArray[i].ptr); //反转字符串,使之变成正确的编码 i++; } } void HuffmanTree::run(const char *inFilename, const char *outFilename, const char *secondOutName) { //run函数的实现 //打开inFilename提供输入 ifstream fileIn(inFilename, ios::in); if (!fileIn) { cerr<<"\""<<infilename<<"\" could="" not="" open."<<endl; exit(1); } char ch; int pos; //从文件中读入字符,并统计各个字符个数 fileIn>>ch; while (fileIn && !fileIn.eof()) { pos = findPosition(ch); if (pos != -1) arrayTree[pos].weight++; else insert(ch, 1); fileIn>>ch; } createHuffmanTree(); //构造huffman树 createHuffmanCode(); //对统计字符进行编码 //打开outFilename提供输出 ofstream fileOut(outFilename, ios::out); if (!fileOut) { cerr<<"\""<<outfilename<<"\" could="" not="" open."<<endl; exit(1); } fileIn.clear(); //刷新输入流, 注:ofstream没有flush()方法,而ifstream则有flush()方法 fileIn.seekg(0, ios::beg); //把从inFilename文件中的字符进行编码,并写入outFilename文件 fileIn>>ch; while (fileIn && !fileIn.eof()) { pos = findPosition(ch); if (pos != -1) fileOut<<codearray[pos].ptr; fileIn>>ch; } fileIn.close(); fileOut.close(); //打开outFilename, secondOutName,分别提供输入输出 fileIn.open(outFilename, ios::in); fileOut.open(secondOutName, ios::out); if (!fileIn || !fileOut) { cerr<<"File could not open."<<endl; exit(1); } //把outFileName文件中的编码进行译码,并把译码结果写入secondOutName文件 const int longestLen = getLongestCodeLength(); char *p = new char[longestLen+1]; int k=0; fileIn>>ch; while (fileIn && !fileIn.eof()) { if (k < longestLen) { p[k++]=ch; p[k]='\0'; pos = isEqual(p); if (pos != -1) { fileOut<<arraytree[pos].info; k=0; } } else { cerr<<"The code is wrong."<<endl; exit(1); } fileIn>>ch; } fileIn.close(); fileOut.close(); } //huffman.cpp end //*****************************main.cpp************************* #include "huffman.h" int main() { HuffmanTree tree; //const char *inFileName="in.txt"; const char *inFileName="main.cpp"; const char *outFileName="out1.txt"; const char *secondOutName="out2.txt"; tree.run(inFileName, outFileName, secondOutName); return 0; } //main.cpp end