//哈夫曼编码:对给定串进行不等长加密,每个字母都用0、1表示
//思路:每次选频次最少的结点形成一个树的左右子树,结点值为两子数之和,递归进行,直到建立一棵树
#include<iostream>
#include<cstring>
using namespace std;
int is_Exist[1000];
struct Node
{
char ch;
int times;
Node* LeftNode;
Node* RightNode;
}*list[1000];
int CreatNode()//以字母出现频次建立一颗树
{
char word[1000];
int i = 0; is_Exist[0] = 1;
scanf("%s", &word);
list[0] = new Node;
list[0]->ch = word[0];
list[0]->times = 1;
list[0]->LeftNode = NULL;
list[0]->RightNode = NULL;
i++;
for (int j =1; j < strlen(word); j++)
{
int is_occur = 0;
int k;
for( k = 0; k < i; k++)
{
if (list[k]->ch == word[j]){
is_occur = 1;
list[k]->times++;
break;
}
}
if (is_occur == 0) {
list[i] = new Node;
list[i]->ch = word[j];
list[i]->times = 1;
list[i]->LeftNode = NULL;
list[i]->RightNode = NULL;
is_Exist[i] = 1;
i++;
}
}
return i;
}
int Start_Code(int i,int num)//i是数组总长度 num是没进树的叶子个数 递归进行加密
{
int is_num =0;
for (int j = 0; j < i; j++)
{
if (is_Exist[j] == 1)
{
is_num++;
}
}
if (is_num== 1) return i;
else
{
int min1 = 0, min2 = 0;
for (int j = 0; j < i; j++)
{
if (is_Exist[j] == 1)
{
min1 = j;
break;
}
}
for (int j = 0; j < i; j++) {
if (is_Exist[j] == 1 && list[j]->times < list[min1]->times) min1 = j;
}
for (int j = 0; j < i; j++)
{
if (is_Exist[j] == 1&&j!=min1)
{
min2 = j;
break;
}
}
for (int j = 0; j < i; j++) {
if (is_Exist[j] == 1 && list[j]->times <= list[min2]->times&&j != min1) min2 = j;
}
list[i] = new Node; is_Exist[i] = 1;
list[i]->times = list[min1]->times + list[min2]->times;
list[i]->LeftNode = list[min1];
list[i]->RightNode = list[min2];
is_Exist[min1] = 0; is_Exist[min2] = 0;
i++;
Start_Code(i, num);
}
}
void leaf_out(Node* &T)//对于加密之后的叶子路径挨个进行输出
{
printf("编码方式如下:\n");
Node* buffer[1000];//层次遍历存结点
string re[1000];//和buffer一一对应 用来保存每个结点的路径
buffer[0] = T;
re[0] = "";
int p = 0, q = 1;//p是当前扫到的元素下标 q是应扫到的元素下标
if (T != NULL)
{
buffer[0] = T;//新建一个buffer数组 让第一个元素为树的根结点
for (p = 0; p<q; p++)
{
int w = 0;
if (buffer[p]->LeftNode != NULL)//如果左节点不为空 即把这个节点放到队尾(下层遍历时遍历到)
{
buffer[q] = buffer[p]->LeftNode;
re[q].assign(re[p]);
re[q]=re[q].append("1");
q++;
w = 1;
}
if (buffer[p]->RightNode != NULL)//如果右节点不为空 即把这个节点放到队尾(下层遍历时遍历到)
{
buffer[q] = buffer[p]->RightNode;
re[q].assign(re[p]);
re[q] = re[q].append("0");
q++;
w= 1;
}
if (w == 0)
{
printf("%c:", buffer[p]->ch);
for (int i = 0; i <re[p].size(); i++) printf("%c", re[p][i]);
printf("\n");
}
}
}
else
{
printf("NULL");
}
}
int main()
{
int num_leaf=CreatNode();
int num_lastnode = Start_Code(num_leaf, num_leaf)-1;
leaf_out(list[num_lastnode]);
return 0;
}
//第一次码博客 光贴代码得了