|
发表于 2020-11-1 19:05:40
|
显示全部楼层
没有看你的错误,提供个完整的仅供参考
- #include<iostream>
- #include<string>
- #include<limits.h>
- using namespace std;
- struct HNode //树结点(静态三叉链表)
- {
- char name; //结点内容
- int weight; //结点权重
- int parent; //双亲数组下标
- int LChild; //左孩子数组下标
- int RChild; //右孩子数组下标
- };
- struct HCode //编码表中的每个元素
- {
- char data; //字符内容
- string code; //对应编码
- };
- static int a[128] = { 0 }; //权值数组
- static char name[128] = ""; //字符内容
- static int n = 0; //字符种类数
- class Huffman
- {
- private:
- HNode* HTree = NULL; //哈夫曼树
- HCode* HCodeTable = NULL; //存储编码表
- int N=0; //叶子数量
- void code(int i, string newcode); //递归函数,对第i个结点编码
- public:
-
- void CreateHTree(int a[], int n, char *name); //创建哈夫曼树
- void CreateCodeTable(); //创建编码表
- void Encode(char* d,string &s); //编码
- void Decode(char* s,char *d); //解码
- void PrintHCodeTable(); //打印编码表
- void PrintHTree(); //打印哈夫曼树
- void printHfmTree(int root, int height, ostream& out);//直观打印
- void Analyze(string s,char *d); //分析压缩效果
- ~Huffman(); //析构
- };
- //a[]为每种字符的权值,n为字符种类,name[]为各个字符的内容
- void Huffman::CreateHTree(int a[], int n, char *name)
- {
- N = n; //叶子数
- HCodeTable = new HCode[N];
- HTree = new HNode[2 * N - 1]; //初始化树的每个结点
- for (int i = 0; i < N; i++)
- {
- HTree[i].name = name[i];
- HTree[i].weight = a[i];
- HTree[i].LChild = HTree[i].RChild = HTree[i].parent = -1;
- HCodeTable[i].data = name[i];
- }
- int x=0, y=0; //开始建哈夫曼树
- for (int i = n; i < 2 * N - 1; i++) //N个叶子,2*N-1个结点
- {
- int min1 = INT_MAX;//最小值,INT_MAX在<limits.h>中定义的
- int min2 = INT_MAX;//次小值
- for(int j = 0; j < i;j++)
- {
- if (HTree[j].parent == -1)
- {
- if (HTree[j].weight < min1)
- {
- min2 = min1;
- min1 = HTree[j].weight;
- y = x;
- x = j;
- }
- else if ((HTree[j].weight >= min1) && (HTree[j].weight < min2))
- {
- min2 = HTree[j].weight;
- y = j;
- }
- else { ; }
- }
- }
- HTree[x].parent = HTree[y].parent = i; //父结点下标(实际意义:三结点相连)
- HTree[i].weight = HTree[x].weight + HTree[y].weight;
- HTree[i].LChild = x;
- HTree[i].RChild = y;
- HTree[i].parent = -1; //待定,默认-1
- }
- }
- //递归函数,对第i个结点编码
- void Huffman::code(int i, string newcode)
- {
- if (HTree[i].LChild == -1) //左子树空
- {
- HCodeTable[i].code = newcode;
- return;
- }
- code(HTree[i].LChild, newcode + "0");
- code(HTree[i].RChild, newcode + "1");
- }
- //生成编码表
- void Huffman::CreateCodeTable()
- {
- code(2 * N - 2, "");
- }
- //打印编码表
- void Huffman::PrintHCodeTable()
- {
- cout << "\t\t\t\t所建字符编码表如下:" << endl;
- cout << "\t\t\t\t--------------------------" << endl;
- cout << "\t\t\t\t字符内容\t" << "对应编码\t" << endl;
- for (int i = 0; i < N; i++)
- {
- cout <<"\t\t\t\t"<< HCodeTable[i].data << "\t\t" << HCodeTable[i].code << endl;
- }
- cout << "\t\t\t\t--------------------------" << endl;
- }
- //析构
- Huffman::~Huffman()
- {
- delete[]HTree;
- delete[]HCodeTable;
- }
- static string coded_string = ""; //用于存储对象字符串的编码串
- static char text_out[] = ""; //存储解码结果
- //编码 d为字符串,s为编码后的编码串
- void Huffman::Encode(char* d,string &s)
- {
- int k = 0;
- while (d[k] != '\0')
- {
- for (int i = 0; i < N; i++)
- {
- if (HCodeTable[i].data == d[k])
- {
- s = s + HCodeTable[i].code;
- break;
- }
- }
- k++;
- }
- cout << "\t\t\t\t编码结果如下: "<< endl;
- cout <<"\t\t\t\t"<< s << endl;
- }
- // 解码 s为编码串,d为解码后的字符串
- void Huffman::Decode(char* s,char* d)
- {
- while (*s != '\0')
- {
- int parent = 2 * N - 2; //根节点在HTree中的下标(共2*N-1个结点)
- while (HTree[parent].LChild != -1) //有左孩子,不是叶子结点
- {
- if (*s == '0')
- parent = HTree[parent].LChild;//左拐
- else
- parent = HTree[parent].RChild;//右拐
- s++;//后移一位
- }//目的:找下标parent
- *d = HCodeTable[parent].data;
- d++;
- }
- }
- //打印Huffman树
- void Huffman::PrintHTree()
- {
- cout << "\t\t\t\t所建哈夫曼静态链表示如下:" << endl;
- cout << "\t\t\t\t==============================================" << endl;
- cout << "\t\t\t\t位置\t"<<"内容\t"<<"权值\t" << "双亲\t" << "左孩子\t" << "右孩子\t" << endl;
- for (int i = 0; i < N * 2 - 1; i++)
- {
- cout <<"\t\t\t\t"<<i<<"\t"<<HTree[i].name<<"\t"<< HTree[i].weight << "\t" << HTree[i].parent << "\t" << HTree[i].LChild << "\t" << HTree[i].RChild<< endl;
- }
- cout << "\t\t\t\t==============================================" << endl;
- //可视化直观打印
- cout << "\t\t\t\t该哈夫曼树打印如下(横向打印):" << endl << endl;
- printHfmTree(2 * N - 2, 0, cout);
- }
- //递归实现直观打印
- void Huffman::printHfmTree(int root, int height, ostream& out)
- {
- char branches[] = { " /\\<" }; //树枝图形
- if (root != -1)
- {
- //先打印当前结点的右子树,并且深度+1
- printHfmTree(HTree[root].RChild, height + 1, out); //递归
- for (int i = 0; i < height; i++) out << "\t";//根据深度,右移
- out << HTree[root].weight;//输出权值
- //叶结点,则再打印出相应的字符
- if (HTree[root].LChild == -1 && HTree[root].RChild == -1)
- out << "(" << HTree[root].name << ")";
- //打印树枝
- out << branches[((HTree[root].LChild != -1) << 1) | (HTree[root].RChild != -1)];
- //换行,打印当前结点的左子树
- out << endl;
- printHfmTree(HTree[root].LChild, height + 1, out); //递归
- }
- }
- //s为编码串,d为原字符串
- void Huffman::Analyze(string s, char* d)
- {
- char* s1 = (char*)s.data();
- double m = 0, n = 0;
- while (*s1 != '\0') { m++; s1++; }
- while (*d != '\0') { n++; d++; }
- cout << "\t\t\t\t压缩比为:" << 100 * (m / 8.0) / n << "%" <<"\n"<< endl;
- }
- //测试函数
- int main()
- {
- Huffman huffman1; //建树(默认构造)
- cout << "请输入需要操作的字符串:" << endl;
- char text[128];
- cin.getline(text, 128, '\n');
- text[strlen(text) + 1] = '\0';
- int str_length = sizeof(text) / sizeof(text[0]);
- char Character_range[] = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 !"#$%&\'()*+,-./:;<=>?@[\]^_`{|}~";
- //给定范围,支持所有可显示字符
- for (int i = 0; i < str_length; i++) //遍历text
- {
- bool p = 0; //标记
- for (int j = 0; j < n; j++)
- {
- if (text[i] == name[j])
- {
- a[j]++; p = 1;
- break;
- }
- }
- for (int j = 0; j < strlen(Character_range)+1 && p == 0; j++)
- {
- if (text[i] == Character_range[j])
- {
- name[n] = text[i];
- a[n]++; n++;
- break;
- }
- }
- }
- int length = 0; //记录长度
- for (int i = 0; i < 128; i++)
- {
- length += a[i];
- }
- char* coded_str = (char*)coded_string.data(); //类型转换,为参数准备
- cout << "\t\t\t\t\t 给定字符串统计结束,系统就绪!\n" << endl;
- cout << "\t\t\t\t Welcome to the Huffman coding system! \n";
- cout << "\t\t\t\t***************************************************\n";
- cout << "\t\t\t\t * │1.打印Huffman树 2.打印编码表 │ *\n";
- cout << "\t\t\t\t * │ │ *\n";
- cout << "\t\t\t\t * │3.编码并打印 4.解码并打印 │ *\n";
- cout << "\t\t\t\t * │ │ *\n";
- cout << "\t\t\t\t * │5.计算压缩率 6.退出程序 │ *\n";
- cout << "\t\t\t\t***************************************************\n";
- cout << endl;
- huffman1.CreateHTree(a, n, name);//建树
- huffman1.CreateCodeTable(); //建表
-
- int select;
- do
- {
- cout << "\t\t\t\t请选择操作方式 (1~6):" << endl;
- cin >> select;
- if (select > 6)
- cout << "错误操作,请重新输入!" << endl;
- else
- switch (select) {
- case 1:
- huffman1.PrintHTree();
- break;
- case 2:
- huffman1.PrintHCodeTable();
- break;
- case 3:
- huffman1.Encode(text,coded_string);
- break;
- case 4:
- coded_str = (char*)coded_string.data(); //类型转换
- huffman1.Decode(coded_str, text_out);
- text_out[length - 2] = '\0';
- cout << "\t\t\t\t解码后的字符串为:" << "\n"<<text_out << "\n"<<endl;
- break;
- case 5:
- huffman1.Analyze(coded_string, text);
- break;
- case 6:
- cout << "\t\t\t\t\tThank you for using!" << endl;
- }
- } while (select != 6);
- }
复制代码 |
|