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

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

生活随笔

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

编程问答

【算法学习笔记】哈夫曼树的构建和哈夫曼编码的实现代码

發(fā)布時(shí)間:2024/9/30 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【算法学习笔记】哈夫曼树的构建和哈夫曼编码的实现代码 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

介紹

哈夫曼(Haffman)這種方法的基本思想如下:
①由給定的n個(gè)權(quán)值{W1,W2,…,Wn}構(gòu)造n棵只有一個(gè)葉子結(jié)點(diǎn)的二叉樹(shù),從而得到一個(gè)二叉樹(shù)的集合F={T1,T2,…,Tn}。
②在F中選取根結(jié)點(diǎn)的權(quán)值最小和次小的兩棵二叉樹(shù)作為左、右子樹(shù)構(gòu)造一棵新的二叉樹(shù),這棵新的二叉樹(shù)根結(jié)點(diǎn)的權(quán)值為其左、右子樹(shù)根結(jié)點(diǎn)權(quán)值之和。
③在集合F中刪除作為左、右子樹(shù)的兩棵二叉樹(shù),并將新建立的二叉樹(shù)加入到集合F中。
④重復(fù)②、③兩步,當(dāng)F中只剩下一棵二叉樹(shù)時(shí),這棵二叉樹(shù)便是所要建立的哈夫曼樹(shù)。

對(duì)于同一組給定葉子結(jié)點(diǎn)所構(gòu)造的哈夫曼樹(shù),樹(shù)的形狀可能不同,但帶權(quán)路徑長(zhǎng)度值是相同的,一定是最小的。

哈夫曼樹(shù)的構(gòu)建

為了方便操作,用靜態(tài)鏈表作為哈夫曼樹(shù)的存儲(chǔ)。 在構(gòu)造哈夫曼樹(shù)時(shí),設(shè)置一個(gè)結(jié)構(gòu)數(shù)組HuffNode保存哈夫曼樹(shù)中各結(jié)點(diǎn)的信息,根據(jù)二叉樹(shù)的性質(zhì)可知,具有n個(gè)葉子結(jié)點(diǎn)的哈夫曼樹(shù)共有2n-1個(gè)結(jié)點(diǎn),所以數(shù)組HuffNode的大小設(shè)置為2n-1,結(jié)點(diǎn)的結(jié)構(gòu)形式如下:

weight lchild rchild parent
其中,weight域保存結(jié)點(diǎn)的權(quán)值,lchild和rchild域分別保存該結(jié)點(diǎn)的左、右孩子結(jié)點(diǎn)在數(shù)組HuffNode中的序號(hào),從而建立起結(jié)點(diǎn)之間的關(guān)系。為了判定一個(gè)結(jié)點(diǎn)是否已加入到要建立的哈夫曼樹(shù)中,可通過(guò)parent域的值來(lái)確定。初始時(shí)parent的值為-1,當(dāng)結(jié)點(diǎn)加入到樹(shù)中時(shí),該結(jié)點(diǎn)parent的值為其雙親結(jié)點(diǎn)在數(shù)組HuffNode中的序號(hào),就不會(huì)是-1了。 構(gòu)造哈夫曼樹(shù)時(shí),首先將由n個(gè)字符形成的n個(gè)葉子結(jié)點(diǎn)存放到數(shù)組HuffNode的前n個(gè)分量中,然后根據(jù)前面介紹的哈夫曼方法的基本思想,不斷將兩個(gè)較小的子樹(shù)合并為一個(gè)較大的子樹(shù),每次構(gòu)成的新子樹(shù)的根結(jié)點(diǎn)順序放到HuffNode數(shù)組中的前n個(gè)分量的后面。

代碼:

#define maxvalue 1e6 //定義最大權(quán)值整數(shù)常量 #define maxleaf 1e3 //定義哈夫曼樹(shù)中結(jié)點(diǎn)個(gè)數(shù)整數(shù)常量 #define maxnode maxleaf*2-1 typedef struct{ int weight; int parent; int lchild; int rchild; }HNodeType; HNodeType* HuffTree(){ HNodeType node[maxnode]; int i,j,n; int m1,m2,x1,x2; cin>>n;//輸入葉子結(jié)點(diǎn)個(gè)數(shù) for(int i = 0;i < n;i++) { node[i].weight=0; node[i].parent=-1; node[i].lchild=-1; node[i].rchild=-1;//初始化結(jié)點(diǎn) } for(int i = 0;i < n;i++) { cin>>node[i].weight;//輸入n個(gè)葉子結(jié)點(diǎn)的權(quán)值 } for(int i = 0;i <n-1;i++){ m1=m2=maxvalue;//注意由于需要最小的和次小的兩個(gè)權(quán)值,因此需要設(shè)兩個(gè)變量 x1=x2=0;//一共n-1個(gè)葉節(jié)點(diǎn),一共2n-1個(gè)結(jié)點(diǎn) for(int j=0;j<n+i;j++){ //構(gòu)造哈夫曼樹(shù)if(node[j].weight<m1&&node[j].parent=-1){ m2=m1; m1=node[j].weight; x2=x1;//保存結(jié)點(diǎn)的下標(biāo) x1=j;} else if(node[j].weight<m2&&node[j].parent=-1){ m2=node[j].weight; x2=j; } } //當(dāng)結(jié)點(diǎn)加入到樹(shù)中時(shí),該結(jié)點(diǎn)parent的值為其雙親結(jié)點(diǎn)在數(shù)組HuffNode中的序號(hào),就不會(huì)是-1了 //現(xiàn)在合并兩棵子樹(shù) 步驟:更新兩棵子樹(shù)的父節(jié)點(diǎn),修改父節(jié)點(diǎn)的權(quán)值,修改父節(jié)點(diǎn)的左右子樹(shù)信息 node[x1].parent=n+i; node[x2].parent=n+i;//最小權(quán)值的結(jié)點(diǎn)和倒數(shù)第二小的權(quán)值結(jié)點(diǎn)的雙親相同 node[n+i].weight=node[x1].weight+node[x2].weight;//記得更新父結(jié)點(diǎn)的權(quán)值 node[n+i].lchild=x1;//修改父節(jié)點(diǎn)的子樹(shù) node[n+i].rchild=x2; } return node; }

哈夫曼編碼

構(gòu)造編碼的時(shí)候人們希望解決的兩個(gè)問(wèn)題是:
①編碼總長(zhǎng)最短。
②譯碼的唯一性。 哈夫曼樹(shù)可用于構(gòu)造使電文的編碼總長(zhǎng)最短的編碼方案。
具體做法如下:設(shè)需要編碼的字符集合為{d1,d2,…,dn},它們?cè)陔娢闹谐霈F(xiàn)的次數(shù)或頻率集合為{w1,w2,…,wn},以d1,d2,…,dn作為葉子結(jié)點(diǎn),w1,w2,…,wn作為它們的權(quán)值,構(gòu)造一棵哈夫曼樹(shù),規(guī)定哈夫曼樹(shù)中的左分支代表0,右分支代表1,則從根結(jié)點(diǎn)到每個(gè)葉子結(jié)點(diǎn)所經(jīng)過(guò)的路徑分支組成的0和1的序列便為該結(jié)點(diǎn)對(duì)應(yīng)字符的編碼,稱(chēng)為哈夫曼編碼。

實(shí)現(xiàn)哈夫曼編碼的算法可分為兩大部分:
①構(gòu)造哈夫曼樹(shù)。
②在哈夫曼樹(shù)上求葉結(jié)點(diǎn)的編碼。
求哈夫曼編碼,實(shí)質(zhì)上就是在已建立的哈夫曼樹(shù)中,從葉子結(jié)點(diǎn)開(kāi)始,沿結(jié)點(diǎn)的雙親鏈域退回到根結(jié)點(diǎn),每退回一步,就走過(guò)了哈夫曼樹(shù)的一個(gè)分支,從而得到一位哈夫曼碼值。由于一個(gè)字符的哈夫曼編碼是從根結(jié)點(diǎn)到相應(yīng)葉子結(jié)點(diǎn)所經(jīng)過(guò)的路徑上各分支所組成的0、1序列,因此先得到的分支代碼為所求編碼的低位碼,后得到的分支代碼為所求編碼的高位碼。可以設(shè)置一結(jié)構(gòu)數(shù)組HuffCode用來(lái)存儲(chǔ)各字符的哈夫曼編碼信息,數(shù)組元素的結(jié)構(gòu)如下:
bit start
其中,分量bit為一維數(shù)組,用來(lái)保存字符的哈夫曼編碼,start表示該編碼在數(shù)組bit中的開(kāi)始位置。所以,對(duì)于第i個(gè)字符,它的哈夫曼編碼存放在HuffCode[i].bit中的從HuffCode[i].start到n的分量上。
算法實(shí)現(xiàn);(寫(xiě)法一)

#define maxbit 1e6 //定義編碼的最大長(zhǎng)度整數(shù)常量 typedef struct{ int bit[maxbit]; int start;}Hcode; void HuffCode(){ node huffnode[maxnode];//node為上面的代碼定義的結(jié)點(diǎn)類(lèi)型 Hcode huffcode[maxcode],cd;//cd為一臨時(shí)編碼結(jié)點(diǎn) int i,j,c,p; huffnode=HuffTree();//HuffTree為上面實(shí)現(xiàn)的建立哈夫曼樹(shù)的函數(shù) for(int i = 0;i < n;i++) { cd.start=n-1;//注意start從n-1開(kāi)始 c=i; p=node[c].parent;while(p!=-1) { if(node[p].lchild==c)cd.bit[cd.start]=0; else cd.bit[cd.start]=1; cd.start--; c=p;//從葉節(jié)點(diǎn)往上 p=node[c].parent;//p變成c的父節(jié)點(diǎn) } for(j=cd.start+1;j<n;j++) { Hcode[i].bit[j]=cd.bit[j];}//保存剛剛求出的葉結(jié)點(diǎn)的哈夫曼編碼和編碼的起始位置 Hcode[i].start=cd.start; } for(i=0;i<n;i++) { for(j=start+1,j<n;j++) cout<<Hcode[i].bit[j];//輸出每個(gè)葉結(jié)點(diǎn)的哈夫曼編碼 }

寫(xiě)法二:

typedef HuffNode{ char data;//待編碼的符號(hào) double weight;//符號(hào)出現(xiàn)的頻率 int parent,lchild,rchild; }HTnode,*HuffmanTree;

編碼:從葉結(jié)點(diǎn)回退,左分支記0 右記1

void Code(HuffmanTree &HT,int n,int i,char *code) { //求第i個(gè)字符的編碼 int p,parent,start; char *cd; cd = new char[n]; cd[n-1] = '\0'; start = n-1; p = i;//p是當(dāng)前結(jié)點(diǎn)的下標(biāo) parent = HT[i].parent;//當(dāng)前結(jié)點(diǎn)的父節(jié)點(diǎn)下標(biāo) while(parent != -1) { if(HT[parent].lchild == p) cd[--start] = '0'; else cd[--start] = '1'; p = parent; parent = HT[patent].parent;//沿雙親回退 } strcpy(code,&cd[start]); delete[]cd; }

總結(jié)

以上是生活随笔為你收集整理的【算法学习笔记】哈夫曼树的构建和哈夫曼编码的实现代码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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