生活随笔
收集整理的這篇文章主要介紹了
数据结构——哈弗曼编码问题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
實驗六 基于哈夫曼樹的數據壓縮算法
【實驗目的】
掌握哈夫曼樹的構造算法。掌握哈夫曼編碼的構造算法。
【實驗內容】
問題描述
輸入一串字符,根據給定的字符串中字符出現的頻率建立相應的哈夫曼樹,
構造哈夫曼編碼表,在此基礎上可以對壓縮文件進行壓縮(即編碼),同時可以對
壓縮后的二進制編碼文件進行解壓(即譯碼)。
輸入要求
多組數據,每組數據 1 行,為一個字符串(只考慮 26 個小寫字母即可)。當輸
入字符串為“00”時,輸入結束。
輸出要求
每組數據輸出 2n+3 行(n 為輸入串中字符類別的個數)。第 1 行為統計出來
的字符出現頻率(只輸出存在的字符,格式為字符:頻度),每兩組字符之間用一個
空格分隔,字符按照 ASCII 碼從小到大的順序排列。第 2 行至第 2n 行為哈夫曼樹
的存儲結構的終態(參照實驗提示表 5.2,一行當中的數據用空格分隔)。第 2n+1
行為每個字符的哈夫曼編碼(只輸出存在的字符,格式為字符:編碼),每兩組字符
之間用一個空格分隔,字符按照 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
【實驗提示】
首先,讀入一行字符串,統計每個字符出現的頻率;然后,根據字符出現的頻
率利用提示算法 1 建立相應的哈夫曼樹;最后,根據得到的哈夫曼樹利用算法 2
求出每個字符的哈夫曼編碼。
思路:
該問題使用順序表來存儲哈夫曼樹
char_statiscal()函數統計每種字符出現的次數
CreatHuffmanCode()構建哈弗曼樹數組,共有n個葉子結點,n-1個非葉子結點。
select()函數選取哈弗曼數組中權值最小的兩個葉子結點,返回到CreatHuffmanCode()函數中,用于完成對非葉子結點的構建
并且同時修改葉子結點的父親結點,和非葉子結點的孩子結點
結構體
typedef struct
{
char info;//存儲每一個結點對應的字符
int weight;//權值
int parent,lchild,rchild;
int index;//存儲每一個結點對應的下標
char code[MAXCODE];//存儲每一個字符對應的二進制編碼
}HTNode,*HuffmanTree;
6.CreatHuffmanCode()函數為每種字符創建各自的二進制編碼
encode()將每個字符的編碼放到該葉子結點的code[]
中去。
具體過程:依次讀入字符,在哈弗曼編碼表(數組中)找到次字符,將字符轉換為編碼表中存放的編碼串。
decode()利用以構建好的哈弗曼樹來進行解碼
對編碼后的文件進行譯碼的過程必須借助于哈弗曼樹。
具體過程:依次讀入文件的二進制碼,從哈弗曼樹的根節點出發,若是0,則走向左子樹,否則走向右子樹。一旦到達葉子結點,便譯出相應的字符編碼。然后繼續從根節點出發繼續譯碼,直到全部結束。
#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
;int weight
;int parent
,lchild
,rchild
;int index
;char code
[MAXCODE
];}HTNode
,*HuffmanTree
;
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
++;}}}
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;}}
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;}}}
void createHuffmanTree(HuffmanTree
&HT
,int n
,char *alphabet
)
{
if(n
<1)return ;int m
=2*n
-1;int number
=0;HT
=new HTNode
[m
+1];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("下標為%d的權為 %d 父親節點:%d,左孩子:%d,右孩子:%d\n",HT
[a
].index
,HT
[a
].weight
,HT
[a
].parent
,HT
[a
].lchild
,HT
[a
].rchild
);}}
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");
}
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
);
}
void decode(char *sum
,int n
,HuffmanTree HT
)
{int index
=2*n
-1;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");}
關于n個字符的哈弗曼編碼的計算時間復雜度為(nlogn)
因為最小堆的插入和刪除都需要(logn)的時間,而n-1次的合并就需要n(logn)
總結
以上是生活随笔為你收集整理的数据结构——哈弗曼编码问题的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。