数据结构-Huffman压缩图片-Huffman编码

Huffman压缩图片:

github项目地址

实现结果输出:
运行结果

  • 实现方式见注释

HuffmanCode.cpp

// HuffmanCode.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
/*
创建工程。
2、读取源文件。
3、生成哈夫曼树。
4、生成哈夫曼编码。
5、压缩原文件。
6、保存压缩文件。
7、扩展功能。
*/
#include <iostream>
#include<string>
#include"Compress.hpp"
using namespace std;
int main(){
    int sign = 0;
    Compress *compress=new Compress();
    cout << "-----------------------哈夫曼图片压缩实现-----------------------"<<endl;
    cout << "输入文件名(路径):" << endl;
    char path[100] = { "C:\\Users\\HUANGYAOHUI\\Desktop\\Pic.bmp" };
    cout << path << endl;
    //cin >> path;
    compress->CompressFile(path);
    return 0;
}

** Compress.hpp**

#pragma once
#include"HuffmanTree.hpp"
#include<stdlib.h>
#include<iostream>
struct  HEAD{
	char type[4];	//文件类型
	int length;		//源文件长度
	int wigth[256];	//权值数组
};
class Compress {
public:
	Compress();
	void CompressFile(char filename[]);		//压缩函数
	void SaveFile(char filename[]);
private:
	void readFileNum(char filename[]);			//读取统计字符数
	void InitHead();
private:
	HuffmanTree hfmTree;
	int wigth[256];		//256个字符的权值
	int n;
	bool isOK;
	char* temp;	//压缩结果
	int NumberOld ;
	int NumberNow;
	HEAD head;
};
void Compress::SaveFile(char filename[]) {
	this->InitHead();
	char path[256] = { 0 };
	strcpy(path, filename);
	strcat(path,".huf");
	//打开文件
	FILE* out = fopen(path, "wb");
	fwrite(&head, sizeof(HEAD), 1, out);
	fwrite(temp, sizeof(char),this->NumberNow, out);
	fclose(out);

	cout << "生成压缩文件:" << path << endl;
	cout << "压缩比:" << 100*double(this->NumberNow + sizeof(HEAD) + strlen(path) + 1) / this->NumberOld <<" %"<< endl;
}
//初始化文件头
void Compress::InitHead() {
	strcat(head.type, "HUF");
	head.length = this->NumberOld;
	for(int i=0;i<this->n;i++)
		head.wigth[i] = this->wigth[i];
}
//构造函数
Compress::Compress() {
	memset(this->wigth,0,sizeof(wigth));
	this->isOK = false;
	this->n = 256;
	this->NumberOld = 0;
	this->NumberNow = 0;
}
//压缩函数
void Compress::CompressFile(char filename[]) {
	//读取数据
	this->readFileNum(filename);
	//源文件大小
	cout << "原文件大小:" << this->NumberOld << endl;

	//构建哈夫曼树
	this->hfmTree.createHFM(this->wigth, this->n);
	
	//生成编码表
	this->hfmTree.createCode();

	//获取大小
	this->NumberNow = this->hfmTree.getSize(this->wigth,this->n);
	
	//压缩数据
	this->temp=this->hfmTree.Encode(filename,this->NumberNow);
	
	//保存
	cout << "输入保存路径:" << endl;
	//cin >> path;
	char path[100] = { "C:\\Users\\HUANGYAOHUI\\Desktop\\Pic.bmp" };
	this->SaveFile(path);
	cout << "压缩成功" << endl;
}
//读取统计字符数
void Compress::readFileNum(char filename[]) {
	//以二进制流的方式打开文件
	int ch;
	FILE* in = fopen(filename, "rb");
	if (in == NULL){
		cout << "打开文件失败" << endl;
	}
	//扫描文件,获得权重
	while ((ch = getc(in) )!= EOF){
		wigth[ch]++;
		this->NumberOld++;
	}
	//关闭文件
	fclose(in);
	/*
	for (int i = 0; i < 256; i++)
		cout <<i<<"  :  "<< wigth[i] << endl;
	*/
}

HuffmanTree.hpp

#pragma once
#include<iostream>
#include<cstdio>
#define MAX 1000
#define SIZE 256
using namespace std;
//哈夫曼树节点表
struct HFNode {
	int wight;	//权值
	int parent;	//父节点
	int Lchild;	//左孩子
	int Rchild;	//右孩子
};
//哈夫曼树
class HuffmanTree {
public:
	void createHFM(int wight[],int n);		//构建哈夫曼树
	void createCode();						//生成编码表
	int getSize(int wigth[], int n);		//得到压缩数据字节数
	char* Encode(char filename[], int nSize);			//压缩编码
private:
	int selectMin(int n);					//找到最小权值的位置
	char str2byte(char *s);				//字符串转码
private:
	int n;	//wight数
	HFNode hfTree[MAX];
	string code[MAX];
};
//得到压缩数据字节数
char* HuffmanTree::Encode(char filename[],int nSize) {
	//分配空间
	char *out =(char*)malloc(nSize*sizeof(char));
	//缓存区域
	char temp[SIZE] = {0};
	int pos = 0;
	int ch;
	FILE* in = fopen(filename, "rb");
	if (in == NULL) {
		cout << "打开文件失败" << endl;
	}
	//扫描文件,获得编码
	while ((ch = fgetc(in)) != EOF) {
		strcat(temp, this->code[ch].c_str());
		while (strlen(temp) >= 8) {
			out[pos++] = str2byte(temp);
			for (int i = 0; i < SIZE - 8; i++) {
				temp[i] = temp[i + 8];
			}
		}
	}
	if (strlen(temp) > 0)
		out[pos++]= str2byte(temp);
	//关闭文件
	fclose(in);
	return out;
}
//字符串转码,每八个字节
char HuffmanTree::str2byte(char *s) {
	char b = 0x00;
	for (int i = 0; i <  8; i++) {
		b = b << 1;
		if (s[i] =='1') {
			b = b | 0x01;
		}
	}
	return b;
}
//得到压缩数据字节数
int HuffmanTree::getSize(int wigth[], int Number) {
	int nSize = 0;
	for (int i = 0; i < Number; i++) {
		nSize += wigth[i] * code[i].length();
	}
	nSize = (nSize % 8) ? nSize / 8 + 1 : nSize / 8;
	return nSize;
}
//构造编码表
void HuffmanTree::createCode() {
	//由底向上找
//	cout << "编码序号\t编码表" << endl;
	for (int i = 0; i < this->n; i++) {
		string s;
		int temp=i;
		while (this->hfTree[temp].parent != -1) {
			if (this->hfTree[this->hfTree[temp].parent].Lchild == temp)
				s += '0';
			else
				s += '1';
			temp = this->hfTree[temp].parent;
		}
		reverse(s.begin(), s.end());
		//cout <<i<<"\t"<< s << endl;
		this->code[i] = s;
	}
}
//创建哈夫曼树
void HuffmanTree::createHFM(int wight[], int Number) {
	//哈夫曼树初始化,n个叶子节点有 2n-1个节点
	//如果是小于n的结点(叶子结点),则把每个字节的重复次数作为权值赋给这些该结点
	//其他非叶子结点权值设为0
	this->n = Number;
	for (int i = 0; i < 2 * n - 1; i++){
		if (i < n)	
			this->hfTree[i].wight = wight[i];
		else
			this->hfTree[i].wight = 0;	
		hfTree[i].parent = -1;
		hfTree[i].Lchild = -1;
		hfTree[i].Rchild = -1;
	}
	//构造哈夫曼树的非叶子节点
	for (int i = 0; i < n-1 ; i++) {
		//找到第一第二小的权值
		int minF = this->selectMin(n+i);
		this->hfTree[minF].parent = n+i;	//挂在新节点上
		int minS = this->selectMin(n+i);
		this->hfTree[minS].parent = n+i;	//挂在新节点上
		//合并两个生成新的节点
		this->hfTree[n + i].wight = this->hfTree[minF].wight + this->hfTree[minS].wight;
		this->hfTree[n + i].Lchild = minF;
		this->hfTree[n + i].Rchild = minS;
	}
	//测试输出
	/*
	cout <<  "权值\t"  << "左子树\t"  << "右子树\t" << "父亲节点"<< endl;
	for (int i = 0; i < 2*n-1; i++) {
		cout << this->hfTree[i].wight << "\t" << this->hfTree[i].Lchild << "\t" << this->hfTree[i].Rchild << "\t" << this->hfTree[i].parent << endl;
	}
	*/
}
//找到权值最小的位置
int HuffmanTree::selectMin(int n) {
	int minValue = INT_MAX;
	int minIndex = -1;
	for (int i = 0; i < n; i++) {
		if (this->hfTree[i].wight < minValue && this->hfTree[i].parent == -1) {
			minIndex = i;
			minValue = this->hfTree[i].wight;
		}
	}
	return minIndex;
}

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Huffman编码是一种基于概率的无损数据压缩算法,可以用于压缩各种类型的数据,包括图片。下面是一个简单的C语言实现Huffman编码图片压缩的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_TREE_HT 100 typedef struct node { unsigned char data; unsigned freq; struct node *left, *right; } node; typedef struct heap { unsigned size; unsigned capacity; node **array; } heap; typedef struct huff_code { unsigned char data; char *code; } huff_code; node *new_node(unsigned char data, unsigned freq) { node *temp = (node *)malloc(sizeof(node)); temp->left = temp->right = NULL; temp->data = data; temp->freq = freq; return temp; } heap *new_heap(unsigned capacity) { heap *temp = (heap *)malloc(sizeof(heap)); temp->size = 0; temp->capacity = capacity; temp->array = (node **)malloc(capacity * sizeof(node *)); return temp; } void swap_node(node **a, node **b) { node *temp = *a; *a = *b; *b = temp; } void min_heapify(heap *h, int idx) { int smallest = idx; int left = 2 * idx + 1; int right = 2 * idx + 2; if (left < h->size && h->array[left]->freq < h->array[smallest]->freq) smallest = left; if (right < h->size && h->array[right]->freq < h->array[smallest]->freq) smallest = right; if (smallest != idx) { swap_node(&h->array[smallest], &h->array[idx]); min_heapify(h, smallest); } } node *extract_min(heap *h) { node *temp = h->array[0]; h->array[0] = h->array[h->size - 1]; --h->size; min_heapify(h, 0); return temp; } void insert_heap(heap *h, node *temp) { ++h->size; int i = h->size - 1; while (i && temp->freq < h->array[(i - 1) / 2]->freq) { h->array[i] = h->array[(i - 1) / 2]; i = (i - 1) / 2; } h->array[i] = temp; } void build_heap(heap *h) { int n = h->size - 1; int i; for (i = (n - 1) / 2; i >= 0; --i) min_heapify(h, i); } int is_leaf(node *root) { return !(root->left) && !(root->right); } heap *create_heap(char *data, int *freq, int size) { heap *h = new_heap(size); int i; for (i = 0; i < size; ++i) h->array[i] = new_node(data[i], freq[i]); h->size = size; build_heap(h); return h; } node *build_huffman_tree(char *data, int *freq, int size) { node *left, *right, *top; heap *h = create_heap(data, freq, size); while (h->size > 1) { left = extract_min(h); right = extract_min(h); top = new_node('$', left->freq + right->freq); top->left = left; top->right = right; insert_heap(h, top); } return extract_min(h); } void print_codes(node *root, char *code, int top, huff_code *h_codes) { if (root->left) { code[top] = '0'; print_codes(root->left, code, top + 1, h_codes); } if (root->right) { code[top] = '1'; print_codes(root->right, code, top + 1, h_codes); } if (is_leaf(root)) { h_codes[root->data].data = root->data; h_codes[root->data].code = (char *)malloc((top + 1) * sizeof(char)); memcpy(h_codes[root->data].code, code, top); h_codes[root->data].code[top] = '\0'; } } void encode_image(char *image_path, huff_code *h_codes) { FILE *fp = fopen(image_path, "rb"); if (!fp) { printf("Error opening file %s\n", image_path); exit(1); } fseek(fp, 0L, SEEK_END); int file_size = ftell(fp); fseek(fp, 0L, SEEK_SET); char *image_data = (char *)malloc(file_size * sizeof(char)); fread(image_data, sizeof(char), file_size, fp); fclose(fp); int freq[256] = {0}; int i; for (i = 0; i < file_size; ++i) ++freq[(unsigned char)image_data[i]]; node *root = build_huffman_tree(image_data, freq, 256); char code[MAX_TREE_HT]; print_codes(root, code, 0, h_codes); } void write_codes_to_file(huff_code *h_codes, char *output_file) { FILE *fp = fopen(output_file, "wb"); if (!fp) { printf("Error opening file %s\n", output_file); exit(1); } int i; fwrite(&h_codes[0].data, sizeof(unsigned char), 1, fp); for (i = 0; i < 256; ++i) { if (h_codes[i].code) { fwrite(&h_codes[i].data, sizeof(unsigned char), 1, fp); unsigned char code_len = strlen(h_codes[i].code); fwrite(&code_len, sizeof(unsigned char), 1, fp); fwrite(h_codes[i].code, sizeof(char), strlen(h_codes[i].code), fp); } } fclose(fp); } int main(int argc, char *argv[]) { char *image_path = argv[1]; char *output_file = argv[2]; huff_code h_codes[256] = {0}; encode_image(image_path, h_codes); write_codes_to_file(h_codes, output_file); return 0; } ``` 该代码实现了将指定路径的图片进行Huffman编码压缩,并将压缩后的编码写入指定的输出文件中。其中,`encode_image()`函数用于对图片进行编码,`write_codes_to_file()`函数用于将编码写入文件中。需要注意的是,该代码只实现了压缩部分,解压缩部分需要另外实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值