//使用数组作为载体,但没有较好地直观呈现的方法,因此放弃了用于初始化存储tree向量的init函数以及相应代码
#include<iostream>
#include <vector>
#include<string>
#include<fstream>
using namespace ::std;
struct node
{
size_t left, right, parent, freq, p;
char c;
};
void build(vector<struct node>& nodes);
void sort(vector<struct node>& nodes);
void qsort(vector<struct node>& nodes, size_t low, size_t high);
void swap(vector<struct node>& nodes, size_t low, size_t high);
void encode(vector<struct node>& nodes);
void reverse(string& s);
void decode(vector<struct node>& nodes);
void printTree(vector<struct node>& nodes, int p);
//void init(vector<vector<size_t>>& tree, vector<struct node>& nodes, size_t i, size_t j, size_t p);
string find(vector<struct node>& nodes, char c);
size_t partition(vector<struct node>& nodes, size_t low, size_t high);
int main()
{
long long n;
cout << "请输入字符集长度:" << endl;
cin >> n;//输入字符集长度
vector<struct node> nodes(n + 1);//初始化字符集
cout << "请输入字符及其频率:" << endl;
for (int i = 1; i <= n; i++)
{
cin >> nodes[i].c >> nodes[i].freq;
nodes[i].left = 0;
nodes[i].right = 0;
nodes[i].parent = 0;
nodes[i].p = i;
}//输入字符集内容
build(nodes);//根据字符集建立哈夫曼树
/*
fstream file1, file2, file3, file4;
file1.open("TobeTran.txt", ios::in);//file1用于读取原文
file2.open("CodeFile.txt", ios::out);//file2用于写入编码后的原文
file3.open("TextFile.txt", ios::out);//写入译文
file4.open("TreePrint.txt", ios::out);//写入哈夫曼树
*/
encode(nodes);//编码
decode(nodes);//译码
printTree(nodes, nodes.size() - 1);//输出哈夫曼树
return 0;
}
void build(vector<struct node>& nodes)
{
vector<struct node> s(nodes);
while (s.size() > 2)
{
sort(s);//排序,使向量最后两项一直为频率最低的两项
struct node* tmp = (struct node*)malloc(sizeof(node));
if (tmp == nullptr)
{
exit(-1);
}
tmp->parent = 0;
tmp->left = s[s.size() - 1].p;
tmp->right = s[s.size() - 2].p;
tmp->freq = nodes[tmp->left].freq + nodes[tmp->right].freq;
tmp->p = nodes.size();
for (int i = 0; i < 2; i++)
{
s.pop_back();
}
nodes.push_back(*tmp);
s.push_back(*tmp);
nodes[tmp->left].parent = nodes.size() - 1;
nodes[tmp->right].parent = nodes.size() - 1;
}
}
void sort(vector<struct node>& nodes)
{
size_t len = nodes.size();
qsort(nodes, 1, len - 1);//使用快速排序进行排序
}
void qsort(vector<struct node>& nodes, size_t low, size_t high)
{
size_t pivot;
if (low < high)
{
pivot = partition(nodes, low, high);
qsort(nodes, low, pivot - 1);
qsort(nodes, pivot + 1, high);
}
}
size_t partition(vector<struct node>& nodes, size_t low, size_t high)
{
size_t pivotkey;
pivotkey = nodes[low].freq;
while (low < high)
{
while (low < high && nodes[high].freq <= pivotkey)
{
high--;
}
swap(nodes, low, high);
while (low < high && nodes[low].freq >= pivotkey)
{
low++;
}
swap(nodes, low, high);
}
return low;
}
void swap(vector<struct node>& nodes, size_t low, size_t high)
{
struct node tmp;
tmp = nodes[low];
nodes[low] = nodes[high];
nodes[high] = tmp;
}
void encode(vector<struct node>& nodes)
{
fstream file1, file2;
file1.open("TobeTran.txt", ios::in);//file1用于读取原文
file2.open("CodeFile.txt", ios::out);//file2用于写入编码后的原文
if (!file1.is_open() || !file2.is_open())
{
cout << "fail to open!" << endl;
return;
}
char c;
while ((c = file1.get()) != EOF)
{
if (c >= 'A' && c <= 'Z')
{
string way = find(nodes, c);
file2 << way;
}
else
{
file2 << c;
}
}
}
string find(vector<struct node>& nodes, char c)
{
string s = "";
size_t p = 0;
for (size_t i = 0; i < nodes.size(); i++)
{
if (nodes[i].c == c)
{
p = i;
break;
}
}
while (p != nodes.size() - 1)
{
if (nodes[nodes[p].parent].left == p)
{
s.push_back('0');
}
else
{
s.push_back('1');
}
p = nodes[p].parent;
}
reverse(s);
return s;
}
void reverse(string& s)
{
size_t m = 0, n = s.size() - 1;
while (m < n)
{
char tmp;
tmp = s[m];
s[m] = s[n];
s[n] = tmp;
m++;
n--;
}
}
void decode(vector<struct node>& nodes)
{
fstream file2, file3;
file2.open("CodeFile.txt", ios::out || ios :: in);//file2用于写入编码后的原文
file3.open("TextFile.txt", ios::out);//写入译文
if (!file2.is_open() || !file3.is_open())
{
cout << "fail to open!" << endl;
return;
}
char c;
size_t p = nodes.size() - 1;
while ((c = file2.get()) != EOF)
{
if (c == '1' || c == '0')
{
if (c == '0')
{
p = nodes[p].left;
}
else if (c == '1')
{
p = nodes[p].right;
}
if (nodes[p].left == 0 || nodes[p].right == 0)
{
file3 << nodes[p].c;
p = nodes.size() - 1;
}
}
else
{
file3 << c;
}
}
}
void printTree(vector<struct node>& nodes, int p)
{
fstream file4;
file4.open("TreePrint.txt", ios::out);//写入哈夫曼树
if (nodes[p].left == 0 || nodes[p].right == 0)
{
cout << nodes[p].p << ":frequence:" << nodes[p].freq << "; leftchild:" << nodes[p].left << "; rightchild:" << nodes[p].right << "; parent:" << nodes[p].parent << endl;
file4 << nodes[p].p << ":frequence:" << nodes[p].freq << "; leftchild:" << nodes[p].left << "; rightchild:" << nodes[p].right << "; parent:" << nodes[p].parent << endl;
return;
}
cout << nodes[p].p << ":frequence:" << nodes[p].freq << "; leftchild:" << nodes[p].left << "; rightchild:" << nodes[p].right << "; parent:" << nodes[p].parent << endl;
file4 << nodes[p].p << ":frequence:" << nodes[p].freq << "; leftchild:" << nodes[p].left << "; rightchild:" << nodes[p].right << "; parent:" << nodes[p].parent << endl;
printTree(nodes, nodes[p].left);
printTree(nodes, nodes[p].right);
/*size_t p;
for (p = 0; p < nodes.size(); p++)
{
if (nodes[p].left != 0 || nodes[p].right != 0)
{
cout << p << "的位置为:" << nodes[p].p << " 父节点为:" << nodes[p].parent << " 频率为:" << nodes[p].freq << " 无字符" << " 左孩子为:" << nodes[p].left << " 右孩子为:" << nodes[p].right << endl;
file4 << p << "的位置为:" << nodes[p].p << " 父节点为:" << nodes[p].parent << " 频率为:" << nodes[p].freq << " 无字符" << " 左孩子为:" << nodes[p].left << " 右孩子为:" << nodes[p].right << endl;
}
else
{
cout << p << "的位置为:" << nodes[p].p << " 父节点为:" << nodes[p].parent << " 频率为:" << nodes[p].freq << " 字符为:" << nodes[p].c << " 左孩子为:" << nodes[p].left << " 右孩子为:" << nodes[p].right << endl;
file4 << p << "的位置为:" << nodes[p].p << " 父节点为:" << nodes[p].parent << " 频率为:" << nodes[p].freq << " 字符为:" << nodes[p].c << " 左孩子为:" << nodes[p].left << " 右孩子为:" << nodes[p].right << endl;
}
}
/*vector<vector<size_t>> tree = {{nodes.size() - 1}};//用于存储哈夫曼树的逻辑结构
init(tree, nodes, 0, 0, nodes.size() - 1);
for (int i = 0; i < tree.size(); i++)
{
for (int j = 0; j < tree[i].size(); j++)
{
cout << nodes[tree[i][j]].p << "处节点的权值为" << nodes[tree[i][j]].freq << " 字符为" << nodes[tree[i][j]].c << " 左孩子为" << nodes[tree[i][j]].left << " 右孩子为" << nodes[tree[i][j]].right << " 父节点为" << nodes[tree[i][j]].parent << ' ';
file4 << nodes[tree[i][j]].p << "处节点的权值为" << nodes[tree[i][j]].freq << " 字符为" << nodes[tree[i][j]].c << " 左孩子为" << nodes[tree[i][j]].left << " 右孩子为" << nodes[tree[i][j]].right << " 父节点为" << nodes[tree[i][j]].parent << ' ';
}
cout << endl;
file4 << endl;
}*/
}
/*void init(vector<vector<size_t>>& tree, vector<struct node>& nodes, size_t i, size_t j, size_t p)//初始化tree向量, [i, j]为tree中的位置,p为nods中的位置
{
if (nodes[p].left == 0)
{
return;
}
if (i + 1 >= tree.size())//若tree行数不够,则加入新行
{
while (i + 1 >= tree.size())
{
tree.push_back(vector<size_t>(0));
}
}
if (j + 1 >= tree[i].size())//若行中的位置不够,则加入新位置直到位置足够
{
while (j >= tree[i].size())
{
tree[i].push_back(0);
}
}
tree[i + 1].push_back(nodes[p].left);
tree[i + 1].push_back(nodes[p].right);
init(tree, nodes, i + 1, j, nodes[p].left);//更新左孩子
init(tree, nodes, i + 1, j + 1, nodes[p].right);//更新右孩子
}*/
//void print(vector<struct node>& nodes, int i, int j, int p);
代码功底不太好,敬请批评。