欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++實(shí)現(xiàn)Huffman的編解碼

 更新時(shí)間:2020年04月28日 09:13:45   作者:漆黑烈焰使  
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)Huffman的編解碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

Huffman編碼主要是通過統(tǒng)計(jì)各元素出現(xiàn)的頻率,進(jìn)而生成編碼最終達(dá)到壓縮的目的。

這里是Huffman樹中節(jié)點(diǎn)的結(jié)構(gòu)。

typedef struct Tree
{
 int freq;//頻率
 int key;//鍵值
 struct Tree *left, *right;
 Tree(int fr=0, int k=0,Tree *l=nullptr, Tree *r=nullptr):
  freq(fr),key(k),left(l),right(r){};
}Tree,*pTree;

首先用一個(gè)名為freq的hashtable來記錄各個(gè)元素的頻率:

void read(){
 int a;
 
 std::ios::sync_with_stdio(false);
 while(cin>>a){
  if(freq.find(a)==freq.end()) {freq[a]=1;}
  else {freq[a]++;}
 }
 
}

Huffman樹的構(gòu)建過程如下代碼所示:

void huffman()
{
 int i;
 string c;
 int fr;
 auto it = freq.begin();
 while(it!=freq.end()){
  Tree *pt= new Tree;
  pt->key = it->first;
  pt->freq = it->second;
  it++;
  th.Insert(pt);//此處的th為一種優(yōu)先隊(duì)列
 }
 
 while(true)//構(gòu)建哈夫曼樹
 {
 
  Tree *proot = new Tree;
  pTree pl,pr;
  pl = th.findMin();
  th.Delete(0);
  if(th.isEmpty()){
    th.Insert(pl);
    break;
  }
 
  pr = th.findMin();
  th.Delete(0);
  //合并節(jié)點(diǎn)
  proot->freq = pl->freq + pr->freq;
  std::ios::sync_with_stdio(false);
  proot->left = pl;
  proot->right = pr;
  th.Insert(proot);
  //合并后再插入
 }
 
 string s;
 
 print_Code(th.findMin(), s);
 
 del(th.findMin());
}

其中print_Code和del函數(shù)如下:

void print_Code(Tree *proot, string st)//從根節(jié)點(diǎn)開始打印,左0右1
{
 if(proot == NULL)
  return ;
 if(proot->left)
 {
  st +='0';
 }
 print_Code(proot->left, st);
 std::ios::sync_with_stdio(false);
 if(!proot->left && !proot->right)
 {
  cout<<proot->key<<" ";
  for(size_t i=0; i<st.length(); ++i){
   cout<<st[i];ml+=st[i];
  }
  cout<<endl;encoded[proot->key]=ml;ml="";
 }
 st.pop_back();
 if(proot->right)
  st+='1';
 print_Code(proot->right, st);
}
 
 
void del(Tree *proot)
{
 if(proot == nullptr)
  return ;
 del(proot->left);
 del(proot->right);
 delete proot;
}

至此就完成了Huffman的編碼。

當(dāng)然,由于huffman的編碼都是0或1,因此需要進(jìn)行位的表示才能完成壓縮。注意,位需要以8個(gè)為一組進(jìn)行寫入:

while(in>>a){
   int x=atoi(a.c_str());
   auto m=encoded.find(x);
   //encoded是另外一個(gè)哈希表用于記錄元素及它的編碼
   if(m==encoded.end()) continue;
   else {
     string t=m->second;
     ss+=t;
   }
   
 }
 unsigned char buf = 0;
 int count = 0;
 int i = 0;
 while(ss[i] != '\0')//位寫入,8個(gè)為一組
 {
  buf = buf | ((ss[i++]-'0') << (7 - count));
  count++;
  if (count == 8)
  {
   count = 0;
   fout << buf;
   buf = 0;
  }
 }
 if(count != 0)
  fout << buf;

至此就完成了Huffman的編碼以及壓縮,效果十分可觀:
當(dāng)對69.6M的txt文件(其中含有大約10000000個(gè)數(shù)據(jù))進(jìn)行壓縮時(shí),產(chǎn)生的encoded.bin文件僅為24.6MB:Ubuntu測試環(huán)境:

下面進(jìn)行Huffman解碼的解說:

Huffman解碼首先是根據(jù)編碼表進(jìn)行huffman樹的重建:

void decode(){
 auto it=decoded.begin();
 Tree *p=proot;
 while(it!=decoded.end()){
   string s=it->first;int t=it->second;int i=0;
   while(i<s.length()){
    if(s[i]=='0') {
     if(proot->left==nullptr) proot->left=new Tree(5);
     proot=proot->left;
     }
    else{
     if(proot->right==nullptr) proot->right=new Tree(5);
     proot=proot->right;
     }
    i++;
   }
   proot->data=t;
   proot=p;
   it++;
 }
 
}

然后讀取bin文件的一系列位:

while (f.get(c)){
   stringstream a;
   for (int i = 7; i > 0; i--)
    a<<((c >> i) & 1);
   a<<(c&1);
   m+=a.str();//將位轉(zhuǎn)為字符串
 }

然后用Huffman樹根據(jù)左0右1進(jìn)行查找并輸出:

int i=0;Tree *p=proot;
 
 while(i<m.length()){
   if(m[i]=='0'&&proot->left!=nullptr)
    {proot=proot->left;i++;}
   else if(m[i]=='1'&&proot->right!=nullptr)
    {proot=proot->right;i++;}
   else
    {cout<<proot->data<<endl;proot=p;}
 }

至此就完成了Huffman樹的解碼:

總的來說,Huffman對于大數(shù)據(jù)的壓縮效果是很好的,運(yùn)行時(shí)間也很快,大概需要20s就可以完成對1000000個(gè)數(shù)據(jù)的編碼壓縮。

難點(diǎn)在于位的寫入與讀取,花了相當(dāng)多的精力進(jìn)行操作。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解C++中stoi/stol/stoll函數(shù)的用法

    詳解C++中stoi/stol/stoll函數(shù)的用法

    這篇文章主要為大家詳細(xì)介紹了C++中stoi、stol、stoll函數(shù)的具體用法,文中的示例代碼講解詳細(xì),對我們學(xué)校C++有一點(diǎn)的幫助,需要的可以參考一下
    2023-03-03
  • 基于C中含有if的宏定義詳解

    基于C中含有if的宏定義詳解

    本篇文章是對C中含有if的宏定義進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++生成dll和調(diào)用dll的方法實(shí)例

    C++生成dll和調(diào)用dll的方法實(shí)例

    C++生成dll和調(diào)用dll的方法實(shí)例,需要的朋友可以參考一下
    2013-03-03
  • C語言中的指針以及二級指針代碼詳解

    C語言中的指針以及二級指針代碼詳解

    這篇文章主要介紹了C語言中的指針以及二級指針代碼詳解,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • c++中的const_cast用法大全

    c++中的const_cast用法大全

    const_cast轉(zhuǎn)換符是用來移除變量的const或volatile限定符。對于后者,我不是太清楚,因?yàn)樗婕暗搅硕嗑€程的設(shè)計(jì),今天重點(diǎn)給大家介紹c++中的const_cast用法大全,需要的朋友參考下吧
    2021-07-07
  • C語言實(shí)現(xiàn)2048小游戲

    C語言實(shí)現(xiàn)2048小游戲

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)2048小游戲,注釋清晰,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • C語言入門篇--變量[定義,初始化賦值,外部聲明]

    C語言入門篇--變量[定義,初始化賦值,外部聲明]

    本篇文章是c語言基礎(chǔ)篇,本文對初識c語言的變量、變量的定義、初始化與賦值、變量的分類、含義、外部聲明做了簡要的描述,幫助大家快速入門c語言的世界,更好的理解c語言
    2021-08-08
  • C語言遞歸函數(shù)與漢諾塔問題簡明理解

    C語言遞歸函數(shù)與漢諾塔問題簡明理解

    遞歸(recursive)函數(shù)是“自己調(diào)用自己”的函數(shù),無論是采用直接或間接調(diào)用方式。間接遞歸意味著函數(shù)調(diào)用另一個(gè)函數(shù)(然后可能又調(diào)用第三個(gè)函數(shù)等),最后又調(diào)用第一個(gè)函數(shù)。因?yàn)楹瘮?shù)不可以一直不停地調(diào)用自己,所以遞歸函數(shù)一定具備結(jié)束條件
    2022-07-07
  • C C++ 算法實(shí)例大全

    C C++ 算法實(shí)例大全

    這篇文章主要介紹了C C++ 算法實(shí)例大全,里面大量的實(shí)例介紹,學(xué)習(xí)c語言的朋友可以收藏
    2016-12-12
  • C++ Qt開發(fā)之ComboBox下拉組合框組件用法詳解

    C++ Qt開發(fā)之ComboBox下拉組合框組件用法詳解

    Qt 是一個(gè)跨平臺C++圖形界面開發(fā)庫,利用Qt可以快速開發(fā)跨平臺窗體應(yīng)用程序,在Qt中,ComboBox(組合框)是一種常用的用戶界面控件,它提供了一個(gè)下拉列表,允許用戶從預(yù)定義的選項(xiàng)中選擇一個(gè),本文給大家介紹QComboBox類的一些常用方法,需要的朋友可以參考下
    2023-12-12

最新評論