程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++實現Huffman樹

C++實現Huffman樹

編輯:C++入門知識

#include "stdafx.h"
#include <iostream>
using std::cout;
using std::cin;
using std::endl;

 

//存儲HuffmanTree的數據結構
typedef struct tagHuffmanTree
{
 unsigned int nWeight;
 unsigned int nParent,nLchild,nRchild;   //用於保存節點在數組中的位置
}HTNode, *HuffmanTree;                         // 動態分配數組存儲赫夫曼樹

typedef char* HuffmanCodeLine;
typedef char** HuffmanCode;                 // 動態分配數組存儲赫夫曼編碼表。。二級指針


//從數列中找出parent為0且權值最小的兩個葉節點.. nMin1和nMin2為數組中位置
void SelectMinWeight(HuffmanTree &HT, int nNodeCount, int &nMin1, int &nMin2)
{
 int i = 0;
 int c = 0;
 int nMinWeight1 = 65535;
 int nMinWeight2 = 65535;

 int *pOrder = new int[nNodeCount];
 for (i=1; i<=nNodeCount; ++i)
 {
  if (0 == HT[i].nParent)                           //統計parent為0的節點及下標
  {
   pOrder[c++] = i;
  }
 }

 //比較parent為0的節點中權值大小,獲取權值小的位置
 for (i=0; i<c; ++i)
 {
  // 在每次循環中, 始終將較小值存入nMinWeight1, 較大值存入nMinWeight2;
  // 執行完畢後, nMinWeight1中是最小值, nMinWeight2中是次小值.
  int nTempWeight = HT[pOrder[i]].nWeight;
  if (nTempWeight < nMinWeight1)
  {
   nMinWeight2 = nMinWeight1;
   nMin2 = nMin1;
   nMinWeight1 = nTempWeight;
   nMin1 = pOrder[i];
  }
  else if (nTempWeight < nMinWeight2)
  {
   nMinWeight2 = nTempWeight;
   nMin2 = pOrder[i];
  }
 }

 if (pOrder)
 {
  delete [] pOrder;
  pOrder = NULL;
 }

 return;
}

 

//建樹及獲取葉子節點編碼

void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *pWeight, int nLeafCount)
{
 if (nLeafCount <= 1)
 {
  return;
 }


 //pWeight為存放權值的數組;nLeafCount為葉子節點數目,即待編碼節點數

 int nNodeCount = 2*nLeafCount - 1;                   //總節點數目
 HT = new HTNode[nNodeCount + 1];                 //多申請一個空間,為了0號單元不使用

 HTNode *pTemp = NULL;
 int i = 0;
 //初始化前幾個存儲單元,存放葉子節點。
 for (i=1,pTemp=HT+1; i<=nLeafCount; ++i, ++pTemp, ++pWeight)             //pTemp=HT+1,第0號單元不用
 {
  (*pTemp).nWeight = *pWeight;
  (*pTemp).nParent = 0;
  (*pTemp).nLchild = 0;
  (*pTemp).nRchild = 0;
 }

 

 //初始化HT後幾個存儲單元,均為存放後來生成的Parent節點的、
 for (; i<=nNodeCount; ++i,++pTemp)
 {
  (*pTemp).nWeight = 0;
  (*pTemp).nParent = 0;
  (*pTemp).nLchild = 0;
  (*pTemp).nRchild = 0;
 }

 

 //建立HuffmanTree。
 int nMin1, nMin2;
 for (i=nLeafCount+1; i<=nNodeCount; ++i)
 {
  //在HT[1...i-1]中尋找parent為0且權值最小的兩個。分別為nMin1, nMin2(nMin1, nMin2是在數組中的位置)
  SelectMinWeight(HT, i-1, nMin1, nMin2);
  HT[nMin1].nParent = i;
  HT[nMin2].nParent = i;
  HT[i].nLchild = nMin1;
  HT[i].nRchild = nMin2;
  HT[i].nWeight = HT[nMin1].nWeight + HT[nMin2].nWeight;
 }


 //----------------編碼部分-------------------------------
 //從葉子到根逆向求編碼
 HC = new HuffmanCodeLine[nLeafCount + 1];    //0號單元未用
 char *pCode = new char[nLeafCount];                  //用於保存一個節點的編碼序列
 memset(pCode, 0, nLeafCount);
 //pCode[nLeafCount - 1] = '\0';                                //編碼結束符
 int nStart = 0;
 for (i=1; i<=nLeafCount; ++i)                                  //遍歷葉子節點
 {
  nStart = nLeafCount - 1;                                        //編碼結束符的位置,pCode數組最後一個位置
  int nTempPos;
  unsigned int nParent;
  for (nTempPos=i,nParent=HT[i].nParent; nParent!=0; nTempPos=nParent, nParent=HT[nParent].nParent)
  {
   if (nTempPos == HT[nParent].nLchild)                //默認左子樹賦值0,右子樹賦值1
   {
    pCode[--nStart] = '0';
   }
   else
   {
    pCode[--nStart] = '1';
   }
  }
  HC[i] = new char[ nLeafCount - nStart ];
  strcpy(HC[i], &pCode[nStart]);                             //將一個葉子節點的編碼拷貝
 }

 if (pCode)
 {
  delete [] pCode;
  pCode = NULL;
 }

 return;
}

 

//主程序入口
int _tmain(int argc, _TCHAR* argv[])
{
 int i = 0;
 int nLeafCount = 0;                   //葉子數即為要編碼的節點數
 //int nNodeCount = 0;
 cout<<"Input num of leaf:"<<endl;
 cin>>nLeafCount;
 while (0 == nLeafCount)
 {
  cout<<"Num of leaf can not be 0"<<endl;
  cin>>nLeafCount;
 }

 //申請內存保存字符值和權值
 char *pLetter = new char[nLeafCount];          //保存字符值
 int *pWeight = new int[nLeafCount];              //保存權值
 for (i=0; i<nLeafCount; ++i)
 {
  cout<<"Input letter and weight"<<endl;
  cin>>pLetter[i]>>pWeight[i];
 }

 HuffmanTree HT = NULL;
 HuffmanCode HC = NULL;
 HuffmanCoding(HT, HC, pWeight, nLeafCount);       //調用方法,建立Huffman樹,並獲取編碼序列

 

 for (int i=1; i<=nLeafCount; ++i)                                   //輸出葉子節點的編碼
 {
  cout<<HC[i]<<endl;
 }

 system("pause");

 if (HT)                        //釋放樹資源
 {
  delete [] HT;
  HT = NULL;
 }

 for (int i=1; i<=nLeafCount; ++i)        //釋放存放編碼的資源
 {
  delete [] HC[i];
  HC[i] = NULL;
 }

 if (HC)
 {
  delete [] HC;
  HC = NULL;
 }

 if (pLetter)
 {
  delete [] pLetter;
  pLetter = NULL;
 }
 if (pWeight)
 {
  delete [] pWeight;
  pWeight = NULL;
 }

 return 0;
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved