赫夫曼树编码

来源:互联网 发布:广州租房信息网软件 编辑:程序博客网 时间:2024/05/17 01:06

#include <iostream>
using std::cout;
using std::cin;
using std::endl;

#include <iomanip>
using std::setw;

// ------------赫夫曼树和赫夫曼编码的存储表示-------------
typedef  struct
{
   unsigned int weight;
   unsigned int parent, lchild, rchild;
} HTNode, * HuffmanTree;         // 动态分配数组存储赫夫曼树
typedef  char * HuffmanCodeLine;
typedef  char * * HuffmanCode;   // 动态分配数组存储赫夫曼编码表

void Select(HuffmanTree &HT, int count, int &min1, int &min2);

void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int * w, int n) // 用"引用"!!!??? SLL, 2011-11-06
{                                                                    // !!!指针本身的在存储空间中的位置是一直没变啊. 2011-11-06
   // w存放n个字符的权值(均>0), 构造赫夫曼树HT,
   // 并求出n个字符的赫夫曼编码HC.
   if (n <= 1)
   {
      return;
   }
   int m = 2*n-1;          // n个叶子结点的赫夫曼树共有2*n-1个结点.
   HT = new HTNode[m+1];   // 0号单元未用.
   int i;                  // 循环变量
   HTNode * p;
   for (p=HT+1, i=1; i<=n; ++i, ++p, ++w) // 0号单元未用.
   {
      (*p).weight = *w;
      (*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;
   }
   int s1, s2;
   for (i=n+1; i<=m; ++i)
   {
      // 建赫夫曼树:
      // 在HT[1...i-1]选择parent为0且weight最小的两个结点,
      // 其序号分别为s1和s2.
      Select(HT, i-1, 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;
   }
#if 1
   // ---------从叶子到根逆向求每个字符的赫夫曼编码---------
   HC = new HuffmanCodeLine[n+1];   // 分配n个字符编码的头指针向量
                                    // 也是0号单元未用!!!
   char * cd = new char[n];         // 分配求编码的工作空间
   cd[n-1] = '\0';                  // 编码结束码
   int start;
   for (i=1; i<=n; ++i)
   {
      start = n-1;   // 编码结束符位置
      int l;
      unsigned int f;
      for (l=i, f=HT[i].parent; f!=0; l=f, f=HT[f].parent)
      {
         if (HT[f].lchild == l)
         {
            cd[--start] = '0';
         }
         else
         {
            cd[--start] = '1';
         }
      }
      HC[i] = new char[n - start];
      strcpy(HC[i], &cd[start]);
   }
   delete [] cd;     // 释放工作空间
#else
   // ---------无栈非递归遍历赫夫曼树, 求赫夫曼编码---------
   // ...
#endif
}

void Select(HuffmanTree &HT, int count, int &min1, int &min2)
{
   int i = 0;
   int c = 0;
   int minWeight1 = 0xffff;
   int minWeight2 = 0xffff;
   int * order = new int[count];
   for (i=1; i<=count; ++i)
   {
      if (HT[i].parent == 0)  // 统计parent为0的结点的个数及下标
      {
         order[c++] = i;
      }
   }
   for (i=0; i<c; ++i)
   {  // 在该循环之前, minWeight1==minWeight2;
      // 在每次循环中, 始终将较小值存入minWeight1, 较大值存入minWeight2;
      // 执行完毕后, minWeight1中是最小值, minWeight2中是次小值.
      int d = HT[order[i]].weight;
      if (d < minWeight1)
      {
         minWeight2 = minWeight1;
         min2 = min1;
         minWeight1 = d;
         min1 = order[i];
      }
      else if (d < minWeight2)
      {
         minWeight2 = d;
         min2 = order[i];
      }
   }
   delete [] order;
}

int main()
{
   int i = 0;
   int cntLeaf = 0;
   int cntNode = 0;

   cout << "请输入叶子个数: ";
   cin >> cntLeaf;
   while (cntLeaf == 0)
   {
      cout << "叶子个数不能为0, 请重新输入: ";
      cin >> cntLeaf;
   }

   cntNode = cntLeaf*2-1;
   char * pLetter = new char[cntLeaf];
   int * pWeight = new int[cntLeaf];
   for (i=0; i<cntLeaf; ++i)
   {
      cout << "请分别输入叶子结点的字符值和权值: ";
      cin >> pLetter[i] >> pWeight[i];
   }

   HuffmanTree HT = NULL;
   HuffmanCode HC = NULL;
   HuffmanCoding(HT, HC, pWeight, cntLeaf);

   cout << "Huffman树结构如下:\n";
   cout << setw(7) << "No."
      << setw(6+1) << "weight"
      << setw(6+1) << "parent"
      << setw(6+1) << "lchild"
      << setw(6+1) << "rchild"
      << '\n';
   for (i=0; i<cntNode; ++i)
   {
      cout << setw(6+1) << i+1
         << setw(6+1) << HT[i+1].weight
         << setw(6+1) << HT[i+1].parent
         << setw(6+1) << HT[i+1].lchild
         << setw(6+1) << HT[i+1].rchild
         << '\n';
   }

   cout << "\n各叶子结点的Huffman编码如下:\n";
   for (i=0; i<cntLeaf; ++i)
   {
      cout << pLetter[i] << ' ' << HC[i+1] << '\n';
   }
   return 0;
}

 

原创粉丝点击