記事のディレクトリ
目的
1. 掌握树的存储结构
2. 掌握二叉树的三种遍历方法
3. 掌握 Huffman 树、Huffman 编码等知识和应用
4. 使用 C++、文件操作和 Huffman 算法实现“图片压缩程序”专题编程。
主な設備と消耗品
1. Windows10オペレーティング
システムがインストールされた1台のPC2。Microsoft Visual Studio2019開発環境がPCシステムにインストールされている
以下はこの記事の内容です。以下のケースは参考用です。
1.実験要件
BMP形式の画像ファイルの場合、256の異なるバイトの繰り返し時間をカウントし、各バイトの繰り返し時間を重みとして使用して、256のリーフノードを持つハフマン二分木を構築します。
画像ファイルは、上記のハフマンツリーによって生成されたハフマンコードを使用して圧縮されます。
圧縮ファイルの名前は、元の画像ファイルと同じですが、圧縮後にpic.bmpやpic.bmp.hufなどの接尾辞.huf(元の接尾辞を保持)が追加されます。
2.分析と設計
上記の実験目的と要件によると、導出および実現できる二分木とハフマン画像圧縮ソフトウェアのプロセスは次のとおりです。
①画像ファイルの読み取り、統計的重み
②ハフマンツリーの
生成③ハフマンコードの生成
④画像
ファイルの圧縮⑤圧縮ファイルの保存
1.データ構造の設計
コードは次のとおりです(例):
//定义存储Huffman树的结构体
typedef struct HTNode
{
int weight;//权值
int parent;//父亲节点
int lchild;//左孩子
int rchild;//右孩子
}HTNode, *HuffmanTree;
typedef char** HuffmanCode;//定义哈夫曼编码类型
//文件头
struct HEAD
{
char type[4];//文件类型
int length;//原文件长度
int weight[256];//权值
};
2.コアアルゴリズムの設計
ハフマンツリーを生成するためのアルゴリズム
コードは次のとおりです(例):
void CreateHuffmanTree(HuffmanTree &HT,int* a, int n)//构造哈夫曼树
{
//初始化
HT = new HTNode[2 * n ]; //动态申请2n个空间 ,0号未使用
for (int i = 1; i <= 2 * n-1 ; i++) {
//双亲 ,左右孩子置0
HT[i].parent = HT[i].lchild = HT[i].rchild = 0;
}
for (int i = 1; i <= n; i++) {
//初始化前n个的权值
HT[i].weight = a[i-1];
}
for (int i = n + 1; i <= 2 * n - 1; i++)HT[i].weight = 0;
//选取与合并,删除与加入
for (int k = n+1; k <= 2 * n - 1; k++) {
int s1, s2;
Select(HT, k-1, s1, s2);//选取两个权值最小值的位置
HT[s1].parent = k;
HT[s2].parent = k; //修改父节点
HT[k].lchild = s1; //更新左孩子权值
HT[k].rchild = s2; //更新右孩子权值
HT[k].weight = HT[s1].weight + HT[s2].weight; //更新自己的权值
}
}
//选取两个权值最小值的位置
void Select(HuffmanTree& HT, int i, int& s1, int& s2) {
int minValue = 0x7FFFFFFF;
//找到最小的一个权值
for (int j = 1; j <= i; j++) {
if (HT[j].parent == 0 && HT[j].weight < minValue) {
minValue =HT[j].weight;
s1 = j;
}
}
// cout << "最小权值:" << s1;
minValue = 0x7FFFFFFF;
//找到倒数第二小的权值
for (int j = 1; j <= i; j++) {
if (j != s1 && HT[j].parent == 0 && HT[j].weight < minValue) {
minValue = HT[j].weight;
s2 = j;
}
}
// cout << "\t次之权值:" << s2 << endl;
}
ハフマンコードを生成するアルゴリズム
コードは次のとおりです(例):
//生成Huffman编码
void HuffmanCoding(HuffmanCode& HC, HuffmanTree& HT)
{
//无栈非递归遍历Huffman树,求Huffman编码
char cd[256] = {
'\0' }; //记录访问路径
int cdlen = 0; //记录当前路径长度
for (int i = 1; i < 512; i++) HT[i].weight = 0; //遍历Huffman树时用做节点的状态标志
int p = 511; //根节点
while (p != 0) {
//向左
if (HT[p].weight == 0) {
HT[p].weight = 1;
if (HT[p].lchild != 0) {
p = HT[p].lchild;
cd[cdlen++] = '0';
}
//登记叶子节点的字符的编码
else if (HT[p].rchild == 0) {
HC[p] = (char*)malloc((cdlen + 1) * sizeof(char));
cd[cdlen] = '\0';
strcpy(HC[p], cd);//复制编码
}
}
//向右
else if (HT[p].weight == 1) {
HT[p].weight = 2;
//右孩子为叶子节点
if (HT[p].rchild != 0) {
p = HT[p].rchild;
cd[cdlen++] = '1';
}
}
//退回父节点,编码长度减一
else {
HT[p].weight = 0;
p = HT[p].parent;
cdlen--;
}
}
}
圧縮コーディングアルゴリズム
コードは次のとおりです(例):
//实现压缩编码
int Encode(const char* Filename, const HuffmanCode HC, char* Buffer, const int nSize) {
FILE* in = fopen(Filename, "rb");//打开文件
//开辟缓冲区
Buffer = (char*)malloc(nSize * sizeof(char));
if (!Buffer) {
cerr << "开辟缓冲区失败" << endl;//输出错误信息
return 0;
}
char cd[256] = {
0 };//工作区
int pos = 0;//缓冲区指针
int c;
//扫描文件进行哈夫曼压缩,结果存入缓冲区
while ((c = getc(in)) != EOF) {
strcat(cd, HC[c+1]);//复制HC到cd工作区里
//压缩编码
while (strlen(cd) >= 8) {
Buffer[pos++] = Str2byte(cd);
//截取字符串左边的8个字符,编码成字节
for (int i = 0; i < 256 - 8; i++)cd[i] = cd[i + 8];
//字符串左移8字节
}
}
if (strlen(cd) > 0)Buffer[pos++] = Str2byte(cd);
fclose(in);//关闭文件
return 1;//成功
}
3.テストケースの設計
任意にBMP画像ファイルを作成してその圧縮率を観察し
ます。JPG形式などのインターネット上の任意の形式の画像ファイルを検索してダウンロードし、その圧縮率を観察します。
4.テスト効果
総括する
詳細については、以下のリンクを参照してください。
リンク:Chong Chong
Chong〜Extract Code:bwbw
このコンテンツをコピーして、操作がより便利なBaiduNetdiskモバイルアプリを開きます。