亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

解析C++哈夫曼樹編碼和譯碼的實現(xiàn)

 更新時間:2016年11月15日 17:13:44   作者:Dmego  
本篇文章主要介紹了C++哈夫曼樹編碼和譯碼的實現(xiàn),詳細的講訴了哈夫曼樹編碼的原理,有需要的同學可以了解一下。

一.背景介紹:

給定n個權值作為n個葉子結點,構造一棵二叉樹,若帶權路徑長度達到最小,稱這樣的二叉樹為最優(yōu)二叉樹,也稱為哈夫曼樹(Huffman Tree)。哈夫曼樹是帶權路徑長度最短的樹,權值較大的結點離根較近。

二.實現(xiàn)步驟:

1.構造一棵哈夫曼樹

2.根據創(chuàng)建好的哈夫曼樹創(chuàng)建一張哈夫曼編碼表

3.輸入一串哈夫曼序列,輸出原始字符

三.設計思想:

1.首先要構造一棵哈夫曼樹,哈夫曼樹的結點結構包括權值,雙親,左右孩子;假如由n個字符來構造一棵哈夫曼樹,則共有結點2n-1個;在構造前,先初始化,初始化操作是把雙親,左右孩子的下標值都賦為0;然后依次輸入每個結點的權值

2.第二步是通過n-1次循環(huán),每次先找輸入的權值中最小的兩個結點,把這兩個結點的權值相加賦給一個新結點,,并且這個新結點的左孩子是權值最小的結點,右孩子是權值第二小的結點;鑒于上述找到的結點都是雙親為0的結點,為了下次能正確尋找到剩下結點中權值最小的兩個結點,每次循環(huán)要把找的權值最小的兩個結點的雙親賦值不為0(i).就這樣通過n-1循環(huán)下、操作,創(chuàng)建了一棵哈夫曼樹,其中,前n個結點是葉子(輸入的字符結點)后n-1個是度為2的結點

 3.編碼的思想是逆序編碼,從葉子結點出發(fā),向上回溯,如果該結點是回溯到上一個結點的左孩子,則在記錄編碼的數組里存“0”,否則存“1”,注意是倒著存;直到遇到根結點(結點雙親為0),每一次循環(huán)編碼到根結點,把編碼存在編碼表中,然后開始編碼下一個字符(葉子)

4.譯碼的思想是循環(huán)讀入一串哈夫曼序列,讀到“0”從根結點的左孩子繼續(xù)讀,讀到“1”從右孩子繼續(xù),如果讀到一個結點的左孩子和右孩子是否都為0,如果是說明已經讀到了一個葉子(字符),翻譯一個字符成功,把該葉子結點代表的字符存在一個存儲翻譯字符的數組中,然后繼續(xù)從根結點開始讀,直到讀完這串哈夫曼序列,遇到結束符便退出翻譯循環(huán)

四.源代碼:

/***************************************
目的:1.根據輸入的字符代碼集及其權值集,
構造赫夫曼樹,輸出各字符的赫夫曼編碼
2.輸入赫夫曼碼序列,輸出原始字符代碼
作者:Dmego  時間:2016-11-11
****************************************/
#include<iostream>
#define MAX_MA 1000
#define MAX_ZF 100
using namespace std;

//哈夫曼樹的儲存表示
typedef struct
{
 int weight; //結點的權值
 int parent, lchild, rchild;//雙親,左孩子,右孩子的下標
}HTNode,*HuffmanTree; //動態(tài)分配數組來儲存哈夫曼樹的結點
 
//哈夫曼編碼表的儲存表示
typedef char **HuffmanCode;//動態(tài)分配數組存儲哈夫曼編碼

//返回兩個雙親域為0且權值最小的點的下標
void Select(HuffmanTree HT, int n, int &s1, int &s2)
{
 /*n代表HT數組的長度
 */

 //前兩個for循環(huán)找所有結點中權值最小的點(字符)
 for (int i = 1; i <= n; i++)
 {//利用for循環(huán)找出一個雙親為0的結點
  if (HT[i].parent == 0)
  {
   s1 = i;//s1初始化為i
   break;//找到一個后立即退出循環(huán)
  }
 }
 for (int i = 1; i <= n; i++)
 {/*利用for循環(huán)找到所有結點(字符)權值最小的一個
  并且保證該結點的雙親為0*/
  if (HT[i].weight < HT[s1].weight && HT[i].parent == 0)
   s1 = i;
 }
 //后兩個for循環(huán)所有結點中權值第二小的點(字符)
 for (int i = 1; i <= n; i++)
 {//利用for循環(huán)找出一個雙親為0的結點,并且不能是s1
  if (HT[i].parent == 0 && i != s1)
  {
   s2 = i;//s2初始化為i
   break;//找到一個后立即退出循環(huán)
  } 
 }

 for (int i = 1; i <= n; i++)
 {/*利用for循環(huán)找到所有結點(字符)權值第二小的一個,
  該結點滿足不能是s1且雙親是0*/
  if (HT[i].weight < HT[s2].weight && HT[i].parent == 0 && i!= s1)
   s2 = i;
 }

}

//構造哈夫曼樹
void CreateHuffmanTree(HuffmanTree &HT, int n)
{
/*-----------初始化工作-------------------------*/
 if (n <= 1)
  return;
 int m = 2 * n - 1;
 HT = new HTNode[m + 1];
 for (int i = 1; i <= m; ++i)
 {//將1~m號單元中的雙親,左孩子,右孩子的下標都初始化為0
  HT[i].parent = 0; HT[i].lchild = 0; HT[i].rchild = 0;
 }
 for (int i = 1; i <= n; ++i)
 {
  cin >> HT[i].weight;//輸入前n個單元中葉子結點的權值
 }
/*-----------創(chuàng)建工作---------------------------*/
 int s1,s2;
 for (int i = n + 1; i <= m; ++i)
 {//通過n-1次的選擇,刪除,合并來構造哈夫曼樹
  Select(HT, i - 1, s1, s2);
  /*cout << HT[s1].weight << " , " << HT[s2].weight << endl;*/
  /*將s1,s2的雙親域由0改為i
  (相當于把這兩個結點刪除了,這兩個結點不再參與Select()函數)*/
  HT[s1].parent = i;
  HT[s2].parent = i;
  //s1,與s2分別作為i的左右孩子
  HT[i].lchild = s1;
  HT[i].rchild = s2;
  //結點i的權值為s1,s2權值之和
  HT[i].weight = HT[s1].weight + HT[s2].weight;
 }
}

//從葉子到根逆向求每個字符的哈夫曼編碼,儲存在編碼表HC中
void CreatHuffmanCode(HuffmanTree HT, HuffmanCode &HC, int n)
{
 HC = new char*[n + 1];//分配儲存n個字符編碼的編碼表空間
 char *cd = new char[n];//分配臨時存儲字符編碼的動態(tài)空間
 cd[n - 1] = '\0';//編碼結束符
 for (int i = 1; i <= n; i++)//逐個求字符編碼
 {
  int start = n - 1;//start 開始指向最后,即編碼結束符位置
  int c = i;
  int f = HT[c].parent;//f指向結點c的雙親
  while (f != 0)//從葉子結點開始回溯,直到根結點
  {
   --start;//回溯一次,start向前指向一個位置
   if (HT[f].lchild == c) cd[start] = '0';//結點c是f的左孩子,則cd[start] = 0;
   else cd[start] = '1';//否則c是f的右孩子,cd[start] = 1
   c = f;
   f = HT[f].parent;//繼續(xù)向上回溯
  }
  HC[i] = new char[n - start];//為第i個字符編碼分配空間
  strcpy(HC[i], &cd[start]);//把求得編碼的首地址從cd[start]復制到HC的當前行中
 }
 delete cd;
}

//哈夫曼譯碼
void TranCode(HuffmanTree HT,char a[],char zf[],char b[],int n)
{
 /*
 HT是已經創(chuàng)建好的哈夫曼樹
 a[]用來傳入二進制編碼
 b[]用來記錄譯出的字符
 zf[]是與哈夫曼樹的葉子對應的字符(葉子下標與字符下標對應)
 n是字符個數,相當于zf[]數組得長度
 */

 int q = 2*n-1;//q初始化為根結點的下標
 int k = 0;//記錄存儲譯出字符數組的下標
 int i = 0;
 for (i = 0; a[i] != '\0';i++)
 {//for循環(huán)結束條件是讀入的字符是結束符(二進制編碼)
  //此代碼塊用來判斷讀入的二進制字符是0還是1
  if (a[i] == '0')
  {/*讀入0,把根結點(HT[q])的左孩子的下標值賦給q
   下次循環(huán)的時候把HT[q]的左孩子作為新的根結點*/
   q = HT[q].lchild;
  }
  else if (a[i] == '1')
  {
   q = HT[q].rchild;
  }
  //此代碼塊用來判斷HT[q]是否為葉子結點
  if (HT[q].lchild == 0 && HT[q].rchild == 0)
  {/*是葉子結點,說明已經譯出一個字符
  該字符的下標就是找到的葉子結點的下標*/
   b[k++] = zf[q];//把下標為q的字符賦給字符數組b[]
   q = 2 * n - 1;//初始化q為根結點的下標
   //繼續(xù)譯下一個字符的時候從哈夫曼樹的根結點開始
  }
 }
 /*譯碼完成之后,用來記錄譯出字符的數組由于沒有結束符輸出的
 時候回報錯,故緊接著把一個結束符加到數組最后*/
 b[k] = '\0';
}
//菜單函數
void menu()
{
 cout << endl;
 cout << "  ┏〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓┓" << endl;
 cout << "  ┃  ★★★★★★★哈夫曼編碼與譯碼★★★★★★★  ┃" << endl;
 cout << "  ┃     1. 創(chuàng)建哈夫曼樹      ┃" << endl;
 cout << "  ┃     2. 進行哈夫曼編碼      ┃" << endl;
 cout << "  ┃     3. 進行哈夫曼譯碼      ┃" << endl;
 cout << "  ┃     4. 退出程序       ┃" << endl;
 cout << "  ┗〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓┛" << endl;
 cout << "      <><注意:空格字符用'- '代替><>" << endl;
 cout << endl;
}
void main()
{
 int falg;//記錄要編碼的字符個數
 char a[MAX_MA];//儲存輸入的二進制字符
 char b[MAX_ZF];//存儲譯出的字符
 char zf[MAX_ZF];//儲存要編碼的字符
 HuffmanTree HT = NULL;//初始化樹為空數
 HuffmanCode HC = NULL;//初始化編碼表為空表
 menu();
 while (true)
 {
  int num;
  cout << "<><請選擇功能(1-創(chuàng)建 2-編碼 3-譯碼 4-退出)><>: ";
   cin >> num;
   switch (num)
   {
   case 1 :
    cout << "<><請輸入字符個數><>:";
    cin >> falg;
    //動態(tài)申請falg個長度的字符數組,用來存儲要編碼的字符
    /*char *zf = new char[falg];*/
    cout << "<><請依次輸入" << falg << "個字符:><>: ";
    for (int i = 1; i <= falg; i++)
     cin >> zf[i];
    cout << "<><請依次輸入" << falg << "個字符的權值><>: ";
    CreateHuffmanTree(HT, falg);//調用創(chuàng)建哈夫曼樹的函數
    cout << endl;
    cout << "<><創(chuàng)建哈夫曼成功!,下面是該哈夫曼樹的參數輸出><>:" << endl;
    cout << endl;
    cout << "結點i"<<"\t"<<"字符" << "\t" << "權值" << "\t" << "雙親" << "\t" << "左孩子" << "\t" << "右孩子" << endl;
    for (int i = 1; i <= falg * 2 - 1; i++)
    {
     cout << i << "\t"<<zf[i]<< "\t" << HT[i].weight << "\t" << HT[i].parent << "\t" << HT[i].lchild << "\t" << HT[i].rchild << endl;
    }
    cout << endl;
    break;
   case 2:
    CreatHuffmanCode(HT, HC, falg);//調用創(chuàng)建哈夫曼編碼表的函數
    cout << endl;
    cout << "<><生成哈夫曼編碼表成功!,下面是該編碼表的輸出><>:" << endl;
    cout << endl;
    cout << "結點i"<<"\t"<<"字符" << "\t" << "權值" << "\t" << "編碼" << endl;
    for (int i = 1; i <= falg; i++)
    {
     cout << i << "\t"<<zf[i]<< "\t" << HT[i].weight << "\t" << HC[i] << endl;
    }
    cout << endl;
    break;
   case 3:
    cout << "<><請輸入想要翻譯的一串二進制編碼><>:";
    /*這樣可以動態(tài)的直接輸入一串二進制編碼,
    因為這樣輸入時最后系統(tǒng)會自動加一個結束符*/
    cin >> a;
    TranCode(HT, a, zf, b, falg);//調用譯碼的函數,
     /*這樣可以直接把數組b輸出,因為最后有
     在數組b添加輸出時遇到結束符會結束輸出*/
    cout << endl;
    cout << "<><譯碼成功!翻譯結果為><>:" << b << endl;
    cout << endl;
    break;
   case 4:
    cout << endl;
    cout << "<><退出成功!><>" << endl;
    exit(0);
   default:
    break;
   }
 }
 
 //-abcdefghijklmnopqrstuvwxyz
 //186 64 13 22 32 103 21 15 47 57 1 5 32 20 57 63 15 1 48 51 80 23 8 18 1 16 1
 //000101010111101111001111110001100100101011110110

}

五.運行截圖:

原文鏈接:http://www.cnblogs.com/dmego/p/6064069.html

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • C++面試八股文之STL標準模板庫使用詳解

    C++面試八股文之STL標準模板庫使用詳解

    這篇文章主要為大家介紹了C++面試八股文之STL標準模板庫使用詳解,<BR>有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • 詳解c++ libuv工作隊列

    詳解c++ libuv工作隊列

    這篇文章主要介紹了c++ libuv工作隊列的相關資料,幫助大家更好的理解和使用libuv,感興趣的朋友可以了解下
    2021-02-02
  • C++稀疏矩陣的各種基本運算并實現(xiàn)加法乘法

    C++稀疏矩陣的各種基本運算并實現(xiàn)加法乘法

    今天小編就為大家分享一篇關于C++稀疏矩陣的各種基本運算并實現(xiàn)加法乘法,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-02-02
  • C語言中isalnum()函數和isalpha()函數的對比使用

    C語言中isalnum()函數和isalpha()函數的對比使用

    這篇文章主要介紹了C語言中isalnum()函數和isalpha()函數的對比使用,都可以判斷是否為字母但isalnum的判斷還包括數字,需要的朋友可以參考下
    2015-08-08
  • C++實現(xiàn)編碼轉換的示例代碼

    C++實現(xiàn)編碼轉換的示例代碼

    這篇文章主要介紹了C++實現(xiàn)編碼轉換的示例代碼,幫助大家快捷的實現(xiàn)編碼轉換,感興趣的朋友可以了解下
    2020-08-08
  • OpenCV使用GrabCut實現(xiàn)摳圖功能

    OpenCV使用GrabCut實現(xiàn)摳圖功能

    Grabcut是基于圖割(graph cut)實現(xiàn)的圖像分割算法,它需要用戶輸入一個bounding box作為分割目標位置,實現(xiàn)對目標與背景的分離/分割。本文將使用GrabCut實現(xiàn)摳圖功能,需要的可以參考一下
    2023-02-02
  • C語言光標旋轉與倒計時功能實現(xiàn)示例詳解

    C語言光標旋轉與倒計時功能實現(xiàn)示例詳解

    這篇文章主要為大家介紹了C語言實現(xiàn)光標旋轉與倒計時功能的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2021-11-11
  • 如何利用Matlab繪制出好看的火山圖

    如何利用Matlab繪制出好看的火山圖

    火山圖是散點圖的一種,它將統(tǒng)計測試中的統(tǒng)計顯著性量度和變化幅度相結合,從而能夠幫助快速直觀地識別那些變化幅度較大且具有統(tǒng)計學意義的數據點。本文將通過Matlab繪制好看的火山圖,需要的可以參考一下
    2022-03-03
  • C字符串與C++中string的區(qū)別詳解

    C字符串與C++中string的區(qū)別詳解

    以下是對C字符串與C++中string的區(qū)別進行了詳細的分析介紹,需要的朋友可以過來參考下
    2013-09-09
  • 算法之排列算法與組合算法詳解

    算法之排列算法與組合算法詳解

    這篇文章主要介紹了算法之排列算法與組合算法詳解,本文以字典序法、遞歸法為例講解了排列算法、全組合算法等,需要的朋友可以參考下
    2014-08-08

最新評論