トピック:ハフマンコーディング方式を使用して、通信文字のコーディングとデコードを実現します
効果画像:
- HuffmanTreeを実装するための元の文字列コードを入力します
- HuffmanTreeを実装するための重みを入力します
- 数字、文字、スペース、記号を同時に入力できます
アイデア:
- ①:まず、ハフマンツリーを構築するために、入力文字の重みを処理する必要があります。ここでは、主な入力方法が入力文字列であるため、対応する関数を使用して各文字の重みを計算するか、直接入力します。各文字の重みには2つの方法があり、対応する処理方法は少し異なりますが、通常は同じです。文字の重みを格納するためにダブルタイプの重み配列を定義し、次に格納するためのコード配列を定義しました。繰り返されない各文字は、ユーザーが文字列を入力すると、繰り返される文字が多数ある場合でも正しい重みを計算できるという問題を解決できます。完全な重みが取得されたら、HuffmanTreeの構築を開始できます。
- ②まず、コード配列のサイズに応じて対応する数のハフマンツリーノードを設定し、同時にこれらのノードを初期化してから、ハフマンツリーノードタイプの優先キューqを設定し、ノードの重みに応じて小さいものから大きいものへと進みます。次のHuffmanTreeの正式な構築に備えるための内部ソート。qの最初の2つの要素を取り出してマージするたびに、マージされた各ノードが最小の重みを持つノードであることがわかります。マージしてから、2つのノードのマージされたノードを再びqキューに入れ、qに要素ルートノードが1つだけ残るまでループして、HuffmanTreeを構築します。
- ③HuffmanTreeが構築されたら、再帰関数を使用してHuffmanTreeをトラバースできます。これは、各文字のコードを出力することを目的としています。同時に、HuffmanTreeツリーをシミュレートして、各ノードの重みを出力することもできます。 HuffmanTreeの内部構造をより直感的に確認できます。
- ④デコード処理は、ルートノードと暗号テキストの最初のビットから開始して、入力暗号テキストに従ってハフマンツリーツリーをトラバースするだけで済みます。現在のビットが「0」の場合、現在のノードはルートノードからルートノードに変わります。現在のビットが「1」の場合、現在のノードはルートノードからルートノードの右ノードに変更されるため、ルートノードに左右のノードがなくなるまで、このノードに文字を保存します。印刷後、文字のデコードが実現されます。デコードを続行する場合は、現在のノードを元のルートノードに更新するだけで済みます。
コード:
#include <stdio.h>
#include<windows.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
using namespace std;
vector<char> code;
double weight[256];
int n;
typedef struct HuffTree
{
string code;
char symbol;
double weight;
HuffTree* lchild;
HuffTree* rchild;
} Node,*Nodeptr;
struct cmp
{
bool operator()(Nodeptr & a, Nodeptr & b)
{
return a->weight > b->weight;
}
};
priority_queue<Nodeptr, vector<Nodeptr>, cmp>q;
void codework()
{
cout << "----------欢迎使用霍夫曼树---------" << endl;
cout << "请选择输入字符串原码或者输入权值:" << endl;
cout << "1.输入原码 2.输入权值" << endl;
int x;
cin >> x;
char ch=getchar();
system("cls");
switch (x)
{
case 1:
{
string s;
cout << "请输入原码:";
getline(cin, s);
for (int i = 0; i < s.size(); i++)
{
if (count(code.begin(), code.end(), s[i]) == 0)
code.push_back(s[i]);
weight[s[i]]++;
}
}
break;
case 2:
{
int num;
cout << "请输入要输入多少个字符:";
cin >> num;
for (int i = 0; i < num; i++)
{
getchar();
char x;
double y;
cout << "请输入第" << i + 1 << "个字符" ;
x = getchar();
cout << "请输入第" << i + 1 << "个字符的权值";
cin >> y;
if (count(code.begin(), code.end(), x) == 0)
code.push_back(x);
weight[x]= y;
}
}
break;
}
}
void PrintHuffmanTree(Nodeptr root)
{
cout << root->weight;
if (root->lchild != NULL || root->rchild != NULL)
{
cout << "(";
PrintHuffmanTree(root->lchild);
cout << ",";
PrintHuffmanTree(root->rchild);
cout << ")";
}
}
Nodeptr CreatHuffmanTree()
{
codework();
n = code.size();
for (int i = 0; i <n; i++)
{
Nodeptr CurNode = new Node;
CurNode->symbol = code[i];
CurNode->weight = weight[code[i]];
CurNode->lchild = NULL;
CurNode->rchild = NULL;
q.push(CurNode);
}
for (int i = 1; i <= n - 1; i++)
{
Nodeptr x1 = q.top();
q.pop();
Nodeptr x2 = q.top();
q.pop();
cout << "第" << i<< "次: 取出的左节点x1权值为" << (double)x1->weight << " 取出的右节点x2权值为:" << (double)x2->weight <<" 它们的父节点权值为:"<< (double)(x1->weight + x2->weight) << endl;
Nodeptr NewNode = new Node;
NewNode->symbol = 0;
NewNode->weight = x1->weight + x2->weight;
NewNode->lchild = x1;
NewNode->rchild = x2;
q.push(NewNode);
}
PrintHuffmanTree(q.top());
cout << endl;
return q.top();
}
void Coding(Nodeptr root,string code)
{
if (root->lchild == NULL && root->rchild == NULL)
{
root->code = code;
cout << root->symbol << "的编码为:" << root->code << endl;
return;
}
if (root->lchild != NULL)
{
code +='0';
Coding(root->lchild, code);
code = code.substr(0, code.size() - 1);
}
if (root->rchild != NULL)
{
code += '1';
Coding(root->rchild, code);
code = code.substr(0, code.size() - 1);
}
}
void Decodeing(Nodeptr root)
{
string s, Ciphertext, Plaintext;
cout << "请输入要解码的字符串:";
cin >> s;
Nodeptr temp = root;
for (int i = 0; i < s.size(); i++)
{
if (s[i] == '0')
{
if (temp->lchild != NULL)
{
Ciphertext += '0';
temp = temp->lchild;
}
}
else if (s[i] == '1')
{
Ciphertext += '1';
if (temp->rchild != NULL)
{
temp = temp->rchild;
}
}
if (temp->lchild == NULL && temp->rchild == NULL)
{
Ciphertext += ' ';
Plaintext += temp->symbol;
temp = root;
}
}
for (int i = 0; i < Ciphertext.size(); i++)
cout << Ciphertext[i];
cout << endl;
for (int i = 0; i < Plaintext.size(); i++)
cout << Plaintext[i];
cout << endl;
}
void DestroyHuffmanTree(Nodeptr root)
{
if (root->lchild != NULL)
DestroyHuffmanTree(root->lchild);
if (root->rchild != NULL)
DestroyHuffmanTree(root->rchild);
delete(root);
}
int main()
{
Node* root= CreatHuffmanTree();
Coding(root, "");
Decodeing(root);
DestroyHuffmanTree(root);
return 0;
}