Haffman编码/译码系统(haffman树的学习与应用)

// 哈夫曼编码/译码系统

#include <iostream>
#include <string>
#include <vector>
using namespace std;

// 统计字符信息中出现的字符种类数和各字符出现的次数(频率)
typedef struct charNode {
 char c;
 int  n;
}charNode;

charNode charList[27]; // 0号位置存放字符种类个数

void Frequent() {
 for (int i = 0; i < 27; i++) {
  charList[i].n = 0;
 }
 string s;
 cout << "输入报文(#结束):";
 cin >> s;
 int len = s.length();
 bool flag ;
 for (int i = 0; i < len; i++) {
  flag = false;
  if (s[i] != '#') {
   int p = 1;
   for (; p <= charList[0].n; p++) {
    if (s[i] == charList[p].c) {
     flag = true;
     break;
    }
   }
   if (flag) {
    charList[p].n++;
   }
   else {
    charList[0].n++;
    charList[charList[0].n].c = s[i];
    charList[charList[0].n].n++;
   } 
  }
  else
   break;
 }
}

// 根据字符的种类数和各自出现的次数建立哈夫曼树

typedef struct HaffmanTreeNode {
 int weight;
 int parent, lchild, rchild;
}HaffmanTreeNode,*HaffmanTree;

void Select(HaffmanTree HT, int n, int &s1, int &s2) {
 int i = 0;
 while (HT[i].parent != 0)
  i++;
 s1 = i;
 for (int j = 0; j < n; j++) {
  if (HT[j].parent == 0 && HT[j].weight < HT[s1].weight)
   s1 = j;
 }
 i = 0;
 while ((HT[i].parent != 0) || i == s1)
  i++;
 s2 = i;
 for (int j = 0; j < n; j++) {
  if (HT[j].parent == 0 && HT[j].weight < HT[s2].weight&&j != s1)
   s2 = j;
 }
}

void HuffmanCoding(HaffmanTree &HT,charNode charList[27],vector<string>&HC) {
 int n = charList[0].n; // 叶子节点的个数
 int m = 2 * n - 1; // 总节点个数
 int s1, s2; // 存weight最小的两个节点的索引
 if (n <= 1)
  return;
 HT = (HaffmanTree)malloc(sizeof(HaffmanTreeNode)*m);

 // 创建HaffmanTree 
 HaffmanTree p = HT;
 int i = 1;
 for (; i <= n; i++,p++) {
  p->weight = charList[i].n;
  p->parent = 0;
  p->lchild = 0;
  p->rchild = 0;
 }
 for (; i <= m; i++,p++) {
  p->weight = 0;
  p->parent = 0;
  p->lchild = 0;
  p->rchild = 0;
 }

 for (i = n; i < m; i++) {
  Select(HT, i, s1, s2);
  HT[s1].parent = i;
  HT[s2].parent = i;
  HT[i].lchild = s1;
  HT[i].rchild = s2;
  HT[i].weight = HT[s1].weight + HT[s2].weight;
 }
 
 // 从叶子到根逆向遍历HuffmanTree,完成每个字符的编码
 string tmp = "";

 for (int i = 0; i < n; i++) {
  for (int p = i, q = HT[i].parent; q != 0; p = q, q = HT[q].parent) {
   if (p == HT[q].lchild)
    tmp = tmp + '0';
   else
    tmp = tmp + '1';
  }
  HC[i] = tmp;
  tmp = "";
 }
}

// 从根往下搜索进行解码操作
void HaffmanDecoding(HaffmanTree &HT, vector<string>&HC, int n) {
 int p = 2 * n - 1 -1 ; // p指向根节点
 for (auto it = HC.begin(); it != HC.end(); it++) {
  string tmp((*it).rbegin(), (*it).rend());
  int i = 0;
  while (p != 0 && tmp[i] != '\0') {
   if (tmp[i] == '0')
    p = HT[p].lchild;
   else
    p = HT[p].rchild;
   // 叶子节点
   if (HT[p].lchild == 0 && HT[p].rchild == 0) {
    cout << (*it) << ":" << charList[p + 1].c << endl;
    p = 2 * n - 1 - 1;
   }
   i++;
  }
 }
}


int main() {
 Frequent();
 cout << "length:" << charList[0].n << endl;
 for (int i = 1; i <= charList[0].n; i++) {
  cout << charList[i].c << "," << charList[i].n << endl;
 }
 HaffmanTree HT;
 vector<string> HC(charList[0].n);
 HuffmanCoding(HT, charList, HC);

 cout << endl << "**************HaffmanCoding:*********" << endl;
 for (int i = 0; i < charList[0].n; i++) {
  cout << charList[i + 1].c << ":" << HC[i] << endl;
 }

 cout << endl << "**************HaffmanDeoding:*********" << endl;
 HaffmanDecoding(HT, HC, charList[0].n);

 system("pause");
 return 0;

}

posted @ 2017-02-22 16:40  codingtao  阅读(563)  评论(0编辑  收藏  举报