日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

数据结构——哈弗曼编码问题

發(fā)布時(shí)間:2023/12/4 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构——哈弗曼编码问题 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

實(shí)驗(yàn)六 基于哈夫曼樹(shù)的數(shù)據(jù)壓縮算法
【實(shí)驗(yàn)?zāi)康摹?/p>

  • 掌握哈夫曼樹(shù)的構(gòu)造算法。
  • 掌握哈夫曼編碼的構(gòu)造算法。
    【實(shí)驗(yàn)內(nèi)容】
    問(wèn)題描述
    輸入一串字符,根據(jù)給定的字符串中字符出現(xiàn)的頻率建立相應(yīng)的哈夫曼樹(shù),
    構(gòu)造哈夫曼編碼表,在此基礎(chǔ)上可以對(duì)壓縮文件進(jìn)行壓縮(即編碼),同時(shí)可以對(duì)
    壓縮后的二進(jìn)制編碼文件進(jìn)行解壓(即譯碼)。
    輸入要求
    多組數(shù)據(jù),每組數(shù)據(jù) 1 行,為一個(gè)字符串(只考慮 26 個(gè)小寫(xiě)字母即可)。當(dāng)輸
    入字符串為“00”時(shí),輸入結(jié)束。
    輸出要求
    每組數(shù)據(jù)輸出 2n+3 行(n 為輸入串中字符類別的個(gè)數(shù))。第 1 行為統(tǒng)計(jì)出來(lái)
    的字符出現(xiàn)頻率(只輸出存在的字符,格式為字符:頻度),每?jī)山M字符之間用一個(gè)
    空格分隔,字符按照 ASCII 碼從小到大的順序排列。第 2 行至第 2n 行為哈夫曼樹(shù)
    的存儲(chǔ)結(jié)構(gòu)的終態(tài)(參照實(shí)驗(yàn)提示表 5.2,一行當(dāng)中的數(shù)據(jù)用空格分隔)。第 2n+1
    行為每個(gè)字符的哈夫曼編碼(只輸出存在的字符,格式為字符:編碼),每?jī)山M字符
    之間用一個(gè)空格分隔,字符按照 ASCII 碼從小到大的順序排列。第 2n+2 行為編碼
    后的字符串,第 2n+3 行為解碼后的字符串(與輸入的字符串相同)。
    輸入樣例
    aaaaaaabbbbbccdddd
    aaccb
    00
    輸出樣例
    a:7 b:5 c2 d:4
    1 7 7 0 0
    2 5 6 0 0
    3 2 5 0 0
    4 4 5 0 0
    5 6 6 3 4
    6 1 1 7 2 5
    7 1 8 0 1 6
    a:0 b:10 c:110 d:111
    00000001010101011011011111
    aaaaaaabbbbbccdddd
    a:2 b:1 c:3
    1 2 4 0 0
    2 1 4 0 0
    3 3 5 0 0
    4 3 5 2 1
    5 6 0 3 4
    a:11 b:10 c:0
    111110000
    aabccc
    【實(shí)驗(yàn)提示】
    首先,讀入一行字符串,統(tǒng)計(jì)每個(gè)字符出現(xiàn)的頻率;然后,根據(jù)字符出現(xiàn)的頻
    率利用提示算法 1 建立相應(yīng)的哈夫曼樹(shù);最后,根據(jù)得到的哈夫曼樹(shù)利用算法 2
    求出每個(gè)字符的哈夫曼編碼。
  • 思路:

  • 該問(wèn)題使用順序表來(lái)存儲(chǔ)哈夫曼樹(shù)

  • char_statiscal()函數(shù)統(tǒng)計(jì)每種字符出現(xiàn)的次數(shù)

  • CreatHuffmanCode()構(gòu)建哈弗曼樹(shù)數(shù)組,共有n個(gè)葉子結(jié)點(diǎn),n-1個(gè)非葉子結(jié)點(diǎn)。

  • select()函數(shù)選取哈弗曼數(shù)組中權(quán)值最小的兩個(gè)葉子結(jié)點(diǎn),返回到CreatHuffmanCode()函數(shù)中,用于完成對(duì)非葉子結(jié)點(diǎn)的構(gòu)建
    并且同時(shí)修改葉子結(jié)點(diǎn)的父親結(jié)點(diǎn),和非葉子結(jié)點(diǎn)的孩子結(jié)點(diǎn)

  • 結(jié)構(gòu)體
    typedef struct
    {
    char info;//存儲(chǔ)每一個(gè)結(jié)點(diǎn)對(duì)應(yīng)的字符
    int weight;//權(quán)值
    int parent,lchild,rchild;
    int index;//存儲(chǔ)每一個(gè)結(jié)點(diǎn)對(duì)應(yīng)的下標(biāo)
    char code[MAXCODE];//存儲(chǔ)每一個(gè)字符對(duì)應(yīng)的二進(jìn)制編碼

  • }HTNode,*HuffmanTree;

    6.CreatHuffmanCode()函數(shù)為每種字符創(chuàng)建各自的二進(jìn)制編碼

  • encode()將每個(gè)字符的編碼放到該葉子結(jié)點(diǎn)的code[]
    中去。
    具體過(guò)程:依次讀入字符,在哈弗曼編碼表(數(shù)組中)找到次字符,將字符轉(zhuǎn)換為編碼表中存放的編碼串。

  • decode()利用以構(gòu)建好的哈弗曼樹(shù)來(lái)進(jìn)行解碼
    對(duì)編碼后的文件進(jìn)行譯碼的過(guò)程必須借助于哈弗曼樹(shù)。
    具體過(guò)程:依次讀入文件的二進(jìn)制碼,從哈弗曼樹(shù)的根節(jié)點(diǎn)出發(fā),若是0,則走向左子樹(shù),否則走向右子樹(shù)。一旦到達(dá)葉子結(jié)點(diǎn),便譯出相應(yīng)的字符編碼。然后繼續(xù)從根節(jié)點(diǎn)出發(fā)繼續(xù)譯碼,直到全部結(jié)束。

  • #include<stdio.h> #include<iostream> #include<string.h> using namespace std; #define MAXSTRLEN 255 #define MAXCODE 20char alphabet[26]={0}; char alphabet2[26]; typedef char **HuffmanCode; typedef struct {char String[MAXSTRLEN]; }SqString;typedef struct {char info;//存儲(chǔ)每一個(gè)結(jié)點(diǎn)對(duì)應(yīng)的字符 int weight;//權(quán)值 int parent,lchild,rchild;int index;//存儲(chǔ)每一個(gè)結(jié)點(diǎn)對(duì)應(yīng)的下標(biāo) char code[MAXCODE];//存儲(chǔ)每一個(gè)字符對(duì)應(yīng)的二進(jìn)制編碼 }HTNode,*HuffmanTree;//統(tǒng)計(jì)字符串中每種字符出現(xiàn)的次數(shù) void char_statiscal(SqString &S,char *alphabet,int &num,char *alphabet2) {int i=0,j=0;for(i=0;S.String[i]!='\0';i++){if(S.String[i]>='a'&&S.String[i]<='z')alphabet[S.String[i]-'a']++;}for(int j=0;j<26;j++){if(alphabet[j]>0){printf("%c:%d ",'a'+j,alphabet[j]);num++;}}printf("\n"); int x=0;for(int j=0;j<26;j++){if(alphabet[j]>0){alphabet2[x]='a'+j;x++;}}}//創(chuàng)建一個(gè)簡(jiǎn)單的哈弗曼樹(shù)用于復(fù)制一個(gè)復(fù)雜的哈弗曼樹(shù) 主要用于排序了 void createHuffmanTree2(HuffmanTree &HT,int n,char *alphabet,char*alphabet2) {if(n<1)return ;int m=2*n-1;int number=0;HT=new HTNode[m+1];for(int i=1;i<=n;i++){HT[i].parent=0;HT[i].lchild=0;HT[i].rchild=0;HT[i].index=i;}for(int j=0;j<26;j++){if(alphabet[j]>0)HT[++number].weight=0;}}//HT哈夫曼樹(shù),ht,是用于存儲(chǔ)排序后的哈夫曼樹(shù),n是所要排序的哈夫曼樹(shù)的節(jié)點(diǎn)個(gè)數(shù) void select(HuffmanTree &HT,int length,int &s1,int &s2) { HuffmanTree ht;createHuffmanTree2(ht,length,alphabet,alphabet2);for(int i=1;i<=length;i++){{ ht[i].weight=HT[i].weight;ht[i].index=HT[i].index;}}int temp_index=0;int temp_weight=0;for(int i=1;i<length;i++){for(int j=1;j<=length-i;j++){if(ht[j].weight>ht[j+1].weight){temp_weight=ht[j].weight;ht[j].weight=ht[j+1].weight;ht[j+1].weight=temp_weight;temp_index=ht[j].index;ht[j].index=ht[j+1].index;ht[j+1].index=temp_index;}}}for(int i=1;i<=length;i++){if(HT[ht[i].index].parent==0){s1=ht[i].index;HT[ht[i].index].parent=length+1;break;}}for(int j=1;j<=length;j++){if(HT[ht[j].index].parent==0){s2=ht[j].index;HT[ht[j].index].parent=length+1;break;}}}//構(gòu)建一顆完整的哈夫曼樹(shù) void createHuffmanTree(HuffmanTree &HT,int n,char *alphabet) { //----------------------------創(chuàng)建哈夫曼樹(shù)---------------------// if(n<1)return ;int m=2*n-1;int number=0;HT=new HTNode[m+1];//構(gòu)造哈夫曼樹(shù)節(jié)點(diǎn) 的結(jié)構(gòu)體數(shù)組,0號(hào)單元不占用,其中共有n個(gè)葉子節(jié)點(diǎn),n-1個(gè)非葉子節(jié)點(diǎn);for(int i=1;i<=m;i++){HT[i].info=alphabet2[i-1];HT[i].parent=0;HT[i].lchild=0;HT[i].rchild=0;HT[i].index=i;}for(int j=0;j<26;j++){if(alphabet[j]>0)HT[++number].weight=alphabet[j];} //---------------------------------初始化--------------------------------//int a,b;for(int i=n+1;i<=m;i++){select(HT,i-1,a,b);HT[a].parent=i;HT[b].parent=i;HT[i].lchild=a;HT[i].rchild=b;HT[i].weight=HT[a].weight+HT[b].weight;}for(int a=1;a<=2*n-1;a++){printf("下標(biāo)為%d的權(quán)為 %d 父親節(jié)點(diǎn):%d,左孩子:%d,右孩子:%d\n",HT[a].index,HT[a].weight,HT[a].parent,HT[a].lchild,HT[a].rchild);}}//為每一個(gè)字符創(chuàng)建好各自的二進(jìn)制編碼 void CreatHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n) {HC=new char*[n+1];char *cd;cd=new char[n];cd[n-1]='\0';int start;int c;int f;for(int i=1;i<=n;i++){start=n-1;c=i,f=HT[i].parent;while(f!=0){--start;if(HT[f].lchild==c)cd[start]='0';else cd[start]='1';c=f,f=HT[f].parent;}HC[i]=new char[n-start];strcpy(HC[i],&cd[start]);}delete cd;for(int i=1;i<=n;i++)printf("%c:%s ",alphabet2[i-1],HC[i]);printf("\n"); }//為字符串進(jìn)行編碼 void encode(SqString &S,HuffmanCode HC,int n,HuffmanTree HT,char *sum) {for(int i=0;S.String[i]!='\0';i++){for(int j=1;j<=n;j++){if(S.String[i]==HT[j].info){strcat(sum,HC[j]);strcpy(HT[j].code,HC[j]);break;}}}printf("%s\n",sum); }//對(duì)已經(jīng)編碼好的字符串進(jìn)行解碼 void decode(char *sum,int n,HuffmanTree HT) {int index=2*n-1;//根節(jié)點(diǎn)開(kāi)始 int j=0;while(sum[j]!='\0'){if(sum[j]=='0')index=HT[index].lchild;else index=HT[index].rchild;if(HT[index].lchild==0&&HT[index].rchild==0){printf("%c",HT[index].info);index=2*n-1;}j++;}}int main() {SqString S;do{gets(S.String);HuffmanTree HT;char sum[100]={""};int num=0;char alphabet[26]={0};char_statiscal(S,alphabet,num,alphabet2);createHuffmanTree(HT,num,alphabet);HuffmanCode HC;CreatHuffmanCode(HT,HC,num);encode(S,HC,num,HT,sum);decode(sum,num,HT);printf("\n"); }while(S.String!="00");}







    關(guān)于n個(gè)字符的哈弗曼編碼的計(jì)算時(shí)間復(fù)雜度為(nlogn)
    因?yàn)樽钚《训牟迦牒蛣h除都需要(logn)的時(shí)間,而n-1次的合并就需要n(logn)

    總結(jié)

    以上是生活随笔為你收集整理的数据结构——哈弗曼编码问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。