优先级队列优化的霍夫曼编码(带中文压缩)

利用STL中的优先级队列进行优化

我将压缩和解压分为两部分,其实一些还是是一样的

压缩的时候通过bitset将每8个01串压缩成一个字节,如果最后一个不满足8个,用0补齐,但是要记录最后一个字节实际有多少个有效位,将其存入文件最后一个字节,解压的时候先将文件定位到最后一个字节,取出有效位的个数,压缩文件真正有效的是倒数第二个字节,倒数第一个字节只是记录倒数第二个字节中有几位是有效的,解压的时候根据密码本(记录每个字节的权值)建立哈夫曼树,然后更具哈夫曼树解压文件

压缩代码部分:

#include <iostream>
#include <string>
#include<functional>
#include <map>
#include <vector>
#include <queue>
#include <bitset>
#include <fstream>
#include <cassert>>
#include <algorithm>
using namespace std;
//-------------------- hufuman Node ------------------------------//
typedef struct Node
{

    char ch;
    int freq;
    Node* leftchild;
    Node* rightchild;
    Node* parent;
}Node,*pNode;

struct cmp1
{
    bool operator()(const pNode a, const pNode b)
    {
        return a->freq > b->freq;//这里好坑啊!!!!如果优先级低的要建立大顶堆
    }
};

//--------------------get <string,int>  dic-----------------------
void getdic2(map<char,int>& dic,const char* addr)
{
    char ch;
    ifstream fin;
    fin.open(addr);
    assert(fin.is_open());
    while(fin.get(ch))
    {
        dic[ch]++;
    }
    fin.close();
}
bool cmp(const pair<char, int> &a, const pair<char, int> &b)
{
	return a.second < b.second;
}

//--------------------get lower vector----------------------------
void getvec2(map<char,int>& dic,vector<pair<char,int> >& vec)
{
    using namespace std;
    map<char,int>::iterator p = dic.begin();
    while(p != dic.end())
    {
        vec.push_back(pair<char,int>(p->first,p->second));
        p++;
    }
    sort(vec.begin(),vec.end(),cmp);
}

//--------------------get Node queue------------------------------
void getnopriority_queue( vector<pair<char,int> >& vec, priority_queue<pNode ,vector<pNode>,cmp1 > & deq)
{
    vector<pair<char,int> >::iterator q = vec.begin();
    while(q != vec.end())
    {
        pNode p_Node = new Node;
        p_Node->ch = q->first;
        p_Node->freq = q->second;
       // cout<< p_Node->ch <<" "<< p_Node->freq<<endl;
        p_Node->leftchild = NULL;
        p_Node->rightchild = NULL;
        p_Node->parent = NULL;
        deq.push(p_Node);
        q++;
    }
    //cout<<endl;
}

//----------------------------------------------------------------
pNode findParentNode(pNode &a, pNode &b)
{
    pNode parent = new Node;
    parent->freq = a->freq + b->freq;
    parent->leftchild = a;
    parent->rightchild = b;
    a->parent = NULL;
    b->parent = NULL;
    return parent;
}

//--------------------make hafuman tree---------------------------
pNode makhfmtr( priority_queue<pNode ,vector<pNode>,cmp1 >  dep)
{
    while(dep.size() >= 2)
    {
        pNode x,y;
        x = dep.top();dep.pop();
        y = dep.top();dep.pop();
        //cout<<x->freq<<" "<<y->freq<<endl;
        dep.push(findParentNode(x,y));
    }
    dep.top()->parent = NULL;
    return dep.top();
}

//--------------------利用DFS求哈夫曼编码---------------------------
map <char,string>  hfmList2;
vector<char> V;
void gethfmList2(pNode root)
{
   if(root->leftchild == NULL && root->rightchild == NULL)
   {
       string a;
       for(int i = 0; i < V.size(); i++)
              a += V[i];
       hfmList2[root->ch] = a;
       V.pop_back();
       return;

   }

   if(root->leftchild)
   {
       V.push_back('0');
       gethfmList2(root->leftchild);

   }
   if(root->rightchild)
   {
        V.push_back('1');
        gethfmList2(root->rightchild);
   }

   if(!V.empty())
   {
       V.pop_back();
   }
}

void smallerToFile(const char* addrYuan,const char* addrMudi)
{
    using namespace std;
    ifstream fin;
    fin.open(addrYuan);
    assert(fin.is_open());
    ofstream fout;
    fout.open(addrMudi,ios_base::binary);
    char chFromFile;
    char greatch = 0;
    string str;
    while(1)
    {
        fin.get(chFromFile);
        if(!fin) break;
        str += hfmList2[chFromFile];
        while(str.size() >= 8)
        {
            string str2(str,0,8);
            //cout<<" cxvdf";
            bitset<8> aaa(str2);
            greatch = (char)aaa.to_ulong();
            fout << greatch;
            str.erase(0,8);
        }
    }
    //////////////////////////////////////////////////////////////////////////
    char youxiao = str.size();
    for(char i = youxiao; i <= 7; i++)
    {
        str.append("0");
    }

    bitset<8> aaa(str);
    chFromFile = (char)aaa.to_ulong();
    fout << chFromFile;
    fout << youxiao;//把最后一位剩余的有效位置存起来
    fin.close();
    fout.close();
}

void dicToFile(const char* addr,const  map <char,int> dic)
{
    ofstream fout("密码本.txt");
    map<char,int>::const_iterator pos = dic.begin();
    while(pos != dic.end())
    {
        fout << pos->first << " "<< pos->second << endl;
        pos++;
    }
    fout.close();
}

int main()
{

    map <char,int> dic;
    vector<pair<char,int> > vec;
    priority_queue<pNode ,vector<pNode>,cmp1 > deq;
    getdic2(dic,"原文.txt");
    getvec2(dic,vec);
    getnopriority_queue(vec,deq);
    pNode root = makhfmtr(deq);
    gethfmList2(root);
    dicToFile("密码本",dic);
    smallerToFile("原文.txt","压缩后.txt");
    return 0;
}

解压代码部分:

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <queue>
#include <utility> //pair
#include <bitset>	 //位运算
#include <fstream>
#include <cassert>>//assert
#include <algorithm>//sort
using namespace std;
//-------------------- hufuman node ------------------------------//
typedef struct node
{

    char ch;
    int freq;
    node* leftchild;
    node* rightchild;
    node* parent;
}node,*pnode;

struct cmp2
{
    bool operator()(const pnode a, const pnode b)
    {
        return a->freq > b->freq;
    }
};

//--------------------get <string,int>  dic-----------------------
void getdic(map<char,int>& dic,const char* addr)
{
    char ch;
    ifstream fin;
    fin.open(addr);
    assert(fin.is_open());
    while(fin.get(ch))
    {
        dic[ch]++;
    }
    fin.close();
}

//----------------------------------------------------------------
bool cmp(const pair<char,int> &a,const pair<char,int> &b)
{
    return a.second < b.second;
}
//--------------------get lower vector----------------------------
void getvec(map<char,int>& dic,vector<pair<char,int> >& vec)
{
    using namespace std;
    map<char,int>::iterator p = dic.begin();
    while(p != dic.end())
    {
        vec.push_back(pair<char,int>(p->first,p->second));
        p++;
    }
    sort(vec.begin(),vec.end(),cmp);
}

//--------------------get node queue------------------------------
void getnopriority_queue(const vector<pair<char,int> >& vec, priority_queue<pnode ,vector<pnode>,cmp2 > & deq)
{
    vector<pair<char,int> >::const_iterator q = vec.begin();//pair用const_iterator
    while(q != vec.end())
    {
        pnode p_node = new node;
        p_node->ch = q->first;
        p_node->freq = q->second;
        p_node->leftchild = NULL;
        p_node->rightchild = NULL;
        p_node->parent = NULL;
        deq.push(p_node);
        q++;
    }
}

//----------------------------------------------------------------
pnode findParentNode(pnode &a, pnode &b)
{
    pnode parent = new node;
    parent->freq = a->freq + b->freq;
    parent->leftchild = a;
    parent->rightchild = b;
    a->parent = parent;
    b->parent = parent;
    return parent;
}

//--------------------make hafuman tree---------------------------
pnode makhfmtr( priority_queue<pnode ,vector<pnode>,cmp2 >  dep)
{
    while(dep.size() >= 2)
    {
        pnode x,y;
        x = dep.top();dep.pop();
        y = dep.top();dep.pop();
        dep.push(findParentNode(x,y));
    }
    dep.top()->parent = NULL;
    return dep.top();
}

//-------------------------解压缩---------------------------------------
void jiemiToFile(const char* addrYuan,const char* addrMudi,node* hfmhead)
{
	using namespace std;
	ifstream fin;

	ofstream fout;
	fout.open(addrMudi);

	char ch;
	char quan;
	char youxiao;
	node* ptr = hfmhead;

	fin.open(addrYuan,ios_base::binary);
	assert(fin.is_open());
	fin.seekg(-1,ios_base::end);
	ifstream::pos_type pos;
	fin.get(youxiao);
    fin.seekg(-2,ios_base::end);

	pos = fin.tellg();
	fin.seekg(0,ios_base::beg);

	int i = 0;
	while(1){
		if(fin.tellg() == pos) break;
		fin.get(ch);
		bitset<8> aaa(ch);
		for(i = 7;i >= 0;i--){
			if(0 == aaa[i]){
				ptr = ptr->leftchild;
				if(NULL == ptr->leftchild){
					fout << ptr->ch;
					ptr = hfmhead;
				}
			}else if(1 == aaa[i]){
				ptr = ptr->rightchild;
				if(NULL == ptr->leftchild){
					fout << ptr->ch;
					ptr = hfmhead;
				}
			}
		}
	}
	fin.get(ch);
	bitset<8> last(ch);
	for(i = 7;i >= (8-youxiao);i--){
		if(0 == last[i]){
			ptr = ptr->leftchild;
			if(NULL == ptr->leftchild){
				fout << ptr->ch;
				ptr = hfmhead;
			}
		}else if(1 == last[i]){
			ptr = ptr->rightchild;
			if(NULL == ptr->leftchild){
				fout << ptr->ch;
				ptr = hfmhead;
			}
		}
	}
	fin.close();
	fout.close();
}

//--------------------------------------------------------------------------
void dicFromFile(const char* addr,map<char,int> &dic)
{
	ifstream fin("密码本.txt");
	char ch;
	int num;
	while(1){
		fin.get(ch);
		if(!fin) break;
		fin >> num;
		dic[ch] = num;
		fin.get(ch);
	}
	fin.close();
}

int main()
{
	map <char,int> dic;
	vector<pair<char,int> > vec;
    priority_queue<pnode ,vector<pnode>,cmp2 > deq;
    dicFromFile("密码本.txt",dic);
    getvec(dic,vec);
    getnopriority_queue(vec,deq);
    node* head = makhfmtr(deq);
	jiemiToFile("压缩后.txt","解压后.txt",head);
	return 0;
}
时间: 2024-10-12 09:51:13

优先级队列优化的霍夫曼编码(带中文压缩)的相关文章

霍夫曼编码/译码器

赫夫曼树的应用 1.哈夫曼编码 在数据通信中,需要将传送的文字转换成二进制的字符串,用0,1码的不同排列来表示字符.例如,需传送的报文为"AFTER DATA EAR ARE ART AREA",这里用到的字符集为"A,E,R,T,F,D",各字母出现的次数为{8,4,5,3,1,1}.现要求为这些字母设计编码.要区别6个字母,最简单的二进制编码方式是等长编码,固定采用3位二进制,可分别用000.001.010.011.100.101对"A,E,R,T,F

霍夫曼编码求节省空间

霍夫曼编码将频繁出现的字符采用短编码,出现频率较低的字符采用长编码.具体的操作过程为:i)以每个字符的出现频率作为关键字构建最小优先级队列:ii)取出关键字最小的两个结点生成子树,根节点的关键字为孩子节点关键字之和,并将根节点插入到最小优先级队列中,直至得到一棵最优编码树. 霍夫曼编码方案是基于______策略的.用该方案对包含a到f6个字符的文件进行编码,文件包含100000个字符,每个字符的出现频率(用百分比表示)如表1-3所示,则与固定长度编码相比,该编码方案节省了______存储空间.

基于python的二元霍夫曼编码译码详细设计

一.设计题目 对一幅BMP格式的灰度图像(个人证件照片)进行二元霍夫曼编码和译码 二.算法设计 (1)二元霍夫曼编码: ①:图像灰度处理: 利用python的PIL自带的灰度图像转换函数,首先将彩色图片转为灰度的bmp图像,此时每个像素点可以用单个像素点来表示. ②:二元霍夫曼编码: 程序流程图: 详细设计: 统计像素点频率,首先通过python自带的PIL库的图像像素点读取函数read()获取灰度图像的所有像素点,通过循环遍历每个像素点,将每个出现的像素点值以及其次数以键值对的形式放入到pyt

C语言之霍夫曼编码学习

?1,霍夫曼编码描述哈夫曼树─即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩. 在计算机信息处理中,"哈夫曼编码"是一种一致性编码法(又称"熵编码法"),用于数据的无损耗压缩.这一术语是指使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码.这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目

霍夫曼编码

进行霍夫曼编码前,我们先创建一个霍夫曼树. ⒈将每个英文字母依照出现频率由小排到大,最小在左,如Fig.1. ? ? ⒉每个字母都代表一个终端节点(叶节点),比较F.O.R.G.E.T五个字母中每个字母的出现频率,将最小的两个字母频率相加合成一个新的节点.如Fig.2所示,发现F与O的频率最小,故相加2+3=5. ⒊比较5.R.G.E.T,发现R与G的频率最小,故相加4+4=8. ⒋比较5.8.E.T,发现5与E的频率最小,故相加5+5=10. ⒌比较8.10.T,发现8与T的频率最小,故相加8

贪心算法-霍夫曼编码

霍夫曼编码是一种无损数据压缩算法.在计算机数据处理中,霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度.期望值降低,从而达到无损压缩数据的目的.例如,在英文中,e的出现机率最高,而z的出现概率则最低.当利用霍夫曼编码对一篇英文进行压缩时,e极有可能用一个比特来表示,而z则可能花去25个比特(不是26).用普通的表示方法时,每个

霍夫曼树及霍夫曼编码的C语言实现

从周五开始学习霍夫曼树,一直到今天终于完成,期间遇到了各种各样的棘手的问题,通过一遍遍在纸上分析每一步的具体状态得以解决.现在对学习霍夫曼树的过程加以记录 首先介绍霍夫曼树 霍夫曼树(Huffman Tree),又称最优二叉树,是一类带权路径长度最短的树.假设有n个权值{w1,w2,-,wn},如果构造一棵有n个叶子节点的二叉树,而这n个叶子节点的权值是{w1,w2,-,wn},则所构造出的带权路径长度最小的二叉树就被称为赫夫曼树. 这里补充下树的带权路径长度的概念.树的带权路径长度指树中所有叶

采用霍夫曼编码(Huffman)画出字符串各字符编码的过程并求出各字符编码 --多媒体技术与应用

题目:有一个字符串:cabcedeacacdeddaaaba,问题: (1)采用霍夫曼编码画出编码的过程,并写出各字符的编码 (2)根据求得的编码,求得各编码需要的总位数 (3)求出整个字符串总编码长度,并计算出字符串位数在编码前与编码后的比值 解答: (1)各字符出现频率统计如下表所示. |符号 |出现次数 |出现频率| |--|--|--| | a |7|0.35| |b|2|0.1| |c|4|0.2| |d|4|0.2| |e|3|0.15| 编码过程如下图所示: 各字符编码如下表所示:

基于哈夫曼编码的文件压缩(c++版)

本博客由Rcchio原创 我了解到很多压缩文件的程序是基于哈夫曼编码来实现的,所以产生了自己用哈夫曼编码写一个压缩软件的想法,经过查阅资料和自己的思考,我用c++语言写出了该程序,并通过这篇文章来记录一下自己写该程序学到的东西.因为本人写的程序在压缩率上,还有提升的空间,所以本文将不定期更新,但程序整体的思路不会有较大的改动. 一.基于哈夫曼编码可实现压缩文件的原理分析 在计算机中,数据的存储都是二进制的,并且以字节作为基本的存储单位,像英文字母在文本中占一个字节,汉字占两个字节,我们把这种每一