C語言實現(xiàn)BMP圖像處理(哈夫曼編碼)
哈夫曼(Huffman)編碼是一種常用的壓縮編碼方法,是 Huffman 于 1952 年為壓縮文本文件建立的。它的基本原理是頻繁使用的數(shù)據(jù)用較短的代碼代替,較少使用的數(shù)據(jù)用較長的代碼代替,每個數(shù)據(jù)的代碼各不相同。這些代碼都是二進(jìn)制碼,且碼的長度是可變的。
下面給出具體的 Huffman 編碼算法:
(1) 首先統(tǒng)計出每個符號出現(xiàn)的頻率,上例 S0 到 S7 的出現(xiàn)頻率分別為 4/14,3/14,2/14,1/14,1/14,1/14,1/14,1/14。
(2) 從左到右把上述頻率按從小到大的順序排列。
(3) 每一次選出最小的兩個值,作為二叉樹的兩個葉子節(jié)點,將和作為它們的根節(jié)點,這兩個葉子節(jié)點不再參與比較,新的根節(jié)點參與比較。
(4) 重復(fù)(3),直到最后得到和為 1 的根節(jié)點。
(5) 將形成的二叉樹的左節(jié)點標(biāo) 0,右節(jié)點標(biāo) 1。把從最上面的根節(jié)點到最下面的葉子節(jié)點途中遇到的 0,1 序列串起來,就得到了各個符號的編碼。

產(chǎn)生 Huffman 編碼需要對原始數(shù)據(jù)掃描兩遍。第一遍掃描要精確地統(tǒng)計出原始數(shù)據(jù)中,每個值出現(xiàn)的頻率,第二遍是建立 Huffman 樹并進(jìn)行編碼。由于需要建立二叉樹并遍歷二叉樹生成編碼,因此數(shù)據(jù)壓縮和還原速度都較慢,但簡單有效,因而得到廣泛的應(yīng)用。
第一步:實現(xiàn)哈夫曼編碼與解碼
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
// 結(jié)構(gòu)體
typedef struct Tree
{
int weight; // 權(quán)值
int id; // 后面解碼用到
struct Tree * lchild; // 左孩子
struct Tree * rchild; // 右孩子
}TreeNode;
// 創(chuàng)建哈夫曼樹
TreeNode* createTree(int *arr, int n)
{
int i, j;
TreeNode **temp, *hufmTree;
temp = (TreeNode**)malloc(sizeof(TreeNode*)*n); // 創(chuàng)建結(jié)構(gòu)體指針數(shù)組
for (i = 0; i < n; ++i)
{
temp[i] = (TreeNode*)malloc(sizeof(TreeNode));
temp[i]->weight = arr[i];
temp[i]->lchild = temp[i]->rchild = NULL;
temp[i]->id = i;
}
for (i = 0; i < n - 1; ++i)
{
int small1 = -1, small2; // 存儲最小權(quán)值的兩個節(jié)點
for (j = 0; j < n; ++j) // 第一步:找到最開始兩個非空節(jié)點
{
if (temp[j] != NULL && small1 == -1)
{
small1 = j;
continue;
}
if (temp[j] != NULL)
{
small2 = j;
break;
}
}
for (j = small2; j < n; ++j) // 找到權(quán)值最小的兩個節(jié)點,并將最小的序號賦給small1,次小的賦給small2
{
if (temp[j] != NULL)
{
if (temp[j]->weight < temp[small1]->weight)
{
small2 = small1;
small1 = j;
}
else if (temp[j]->weight < temp[small2]->weight)
{
small2 = j;
}
}
}
hufmTree = (TreeNode*)malloc(sizeof(TreeNode));
hufmTree->lchild = temp[small1];
hufmTree->rchild = temp[small2];
hufmTree->weight = temp[small1]->weight + temp[small2]->weight;
temp[small1] = hufmTree;
temp[small2] = NULL;
}
free(temp);
return hufmTree;
}
// 前序遍歷
void PreOrderTraversal(TreeNode* hufmTree)
{
if (hufmTree)
{
printf("%d", hufmTree->weight);
PreOrderTraversal(hufmTree->lchild);
PreOrderTraversal(hufmTree->rchild);
}
}
// 哈夫曼編碼
void hufmTreeCode(TreeNode* hufmTree,int depth)
{
static int code[10],i;
if (hufmTree)
{
if (hufmTree->lchild == NULL && hufmTree->rchild == NULL)
{
int i=0;
printf("權(quán)值為%d的節(jié)點,哈夫曼編碼為:", hufmTree->weight);
for (i = 0; i < depth; ++i)
{
printf("%d", code[i]);
}
printf("\n");
}
else
{
code[depth] = 0;
hufmTreeCode(hufmTree->lchild, depth + 1);
code[depth] = 1;
hufmTreeCode(hufmTree->rchild, depth + 1);
}
}
}
// 哈夫曼解碼
// 思想:通過定位ID,找到源碼中的位置
void hufmTreeDecode(TreeNode* hufmTree, char a[],char st[])
{
int i,arr[100];
TreeNode* temp;
for (i = 0; i < strlen(a); ++i) // 轉(zhuǎn)化字符串編碼為數(shù)組編碼
{
if (a[i] == '0')
arr[i] = 0;
else
arr[i] = 1;
}
i = 0;
while (i < strlen(a))
{
temp = hufmTree;
while (temp->lchild != NULL && temp->rchild != NULL)
{
if (arr[i] == 0)
temp = temp->lchild;
else
temp = temp->rchild;
i++;
}
printf("%c", st[temp->id]);
}
printf("\n");
free(temp);
}
int main()
{
int i, n, arr[100];
printf("輸入需要創(chuàng)建的節(jié)點個數(shù):\n");
scanf("%d", &n);
printf("輸入權(quán)值:\n");
for (i = 0; i < n; ++i)
scanf("%d", &arr[i]);
printf("\n請輸入每個權(quán)值對應(yīng)的字符:\n");
char st[100];
scanf("%s",st);
// 創(chuàng)建哈夫曼樹
TreeNode* hufmTree;
hufmTree = createTree(arr, n);
// 哈夫曼編碼
printf("\n哈夫曼編碼為:\n");
hufmTreeCode(hufmTree, 0);
// 遍歷
printf("\n前序遍歷:\n");
PreOrderTraversal(hufmTree);
// 解碼
printf("\n請輸入需要解碼的碼字:\n");
char codeSt[100];
scanf("%s",codeSt);
printf("\n解碼的碼字為:\n");
hufmTreeDecode(hufmTree, codeSt, st);
free(hufmTree);
system("pause");
return 0;
}

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C++ Custom Control控件向父窗體發(fā)送對應(yīng)的消息
這篇文章主要介紹了C++ Custom Control控件向父窗體發(fā)送對應(yīng)的消息的相關(guān)資料,需要的朋友可以參考下2015-06-06
使用Libmicrohttpd搭建內(nèi)嵌(本地)服務(wù)器的方法
下面小編就為大家?guī)硪黄褂肔ibmicrohttpd搭建內(nèi)嵌(本地)服務(wù)器的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-08-08
QT連接SQLServer數(shù)據(jù)庫的實現(xiàn)
要使用Qt連接SQL Server數(shù)據(jù)庫,需要使用Qt提供的SQL模塊和SQL Server驅(qū)動程序,具有一定的參考價值,感興趣的可以了解一下2023-09-09

