压缩算法之算术编码

                                音频压缩算法-算术编码

参考:https://blog.csdn.net/qq_36752072/article/details/77986159

一  .算法思路:

1.1编码:

1.首先的准备工作——按照各信源信号好出现的频率,将[0, 1)这个区间分成若干段,那么每个信号源就会有自己        
    对应的区间了;
2.将[0, 1)这个区间设置为初始间隔;
3.然后编码过程就是,按照待处理的信号,一个一个信号源读入,每读入一个信号,就将该信号源在[0, 1)上的范围等比例的缩小到      最新得到的间隔中。
4.然后依次迭代,不断重复进行步骤3,直到最后信号中的信源信号全部读完为止;

伪代码:

    set lowLevel = 0
    set highLevel = 1
    input symbol 
    do 
        delta = highLevel - lowLevel
        lowLevel = lowLevel + delta * symbol[i].lowLevel
        highLevel = highLevl + delta * symbol[i].highLevel
    while symbol traversed
    output lowLevel

1.2解码:

  1. 待解码的数据,首先我们仍然需要在编码时候的那项准备工作,即获取创建一个编码解码表,但是由于我们是在同一个类中完成的,那么我们把该对应表作为类的一个属性就可以实现获取表了;
  2. 准备工作完成之后,我们就可以开始正式的解码工作了,首先判断待解码的数据在哪个范围内,将该范围对应的信源信号输出即可;
  3. 重复步骤2,按理说,按照这样的方法,解码会一直进行下去,无穷不尽,直到达到计算机的精度为止,那么为了正确的进行解码,我们需要对解码的次数进行限定,即我们首先需要事先知道,解码后的信源信号的长度,然后在进行解码,这样才能比较完美的进行解码。

伪代码:

    input code
    do 
        find the Interval which contains the code
        set range = highLevel - lowLevel
        set code = (code - lowLevel) / range
    while times out

二.具体实现

#include<iostream>
#include<map>
#include<string>
using namespace std;

//区间类,主要的就是用来存放上下界
class Range{
	public:
		Range(double l=0.0,double h=1.0,double delta=1.0):low(l),high(h),deltaLevel(delta){}
		double getlow(){ return  this->low;}   //获得下限
		double gethigh() {return this->high;}//获得上限
		double getdalataLevel() {return this->deltaLevel;} //获得区间大小 
		
	private:
		double low;
		double high;
		double deltaLevel;
		
};




//算术编码类
class Arithmeticcoding{
	public:
		Arithmeticcoding(){
			length=0;
		}
		~Arithmeticcoding(){}
	
		void requirecode();   //获得编码,创建初始对应表
		double encode(string str); //编码
		string decode(double value); //解码
		int getLength(); 
	
	private:
		int length;
		std::map<char, Range> map;
};

//获得编码,创建初始对应表
void Arithmeticcoding::requirecode(){
	char ch;
	double l=0.0;
	double h=0.0;
	double probability;
	while(true){
		cin>>ch;
		if(ch=='#'){
			break;
		}else{
			cin>>probability;
			l=h;
			h=h+probability;
			Range range(l,h,probability);
			map.insert(std::pair<char,Range>(ch,range));
		}
	}	
} 

//编码 
double Arithmeticcoding::encode(string str){
	double lowRange=0.0,highRange=1.0;
	for(auto i=str.begin();i!=str.end();++i){
		// 使用map来通过字符完成概率的查找
        // map[*i]表示的就是对应的字符的出现概率
        double delta=highRange-lowRange;
        highRange=lowRange+delta*map[*i].gethigh();
		lowRange=lowRange+delta*map[*i].getlow();
		
		++length;
	}
	return lowRange;
} 

//解码 
string Arithmeticcoding::decode(double value){
	double low,high;
	string symbol="";
	
	// 译出第一个编码
	for(auto i=map.begin();i!=map.end();i++){
		if((i->second).getlow()<value&&(i->second).gethigh()>value){
			low=(i->second).getlow();
			high=(i->second).gethigh();
			symbol+=(i->first);
		}
	} 
	//解码
	for(int i=0;i<length-1;++i){
		double detal;
		detal=high-low;
		value -= low;
		value /= detal;
		
		for(auto j=map.begin();j!=map.end();j++){
			if((j->second).getlow()<value&&(j->second).gethigh()>value){
				low=(j->second).getlow();
				high=(j->second).gethigh();
				symbol+=(j->first);
				break;
			}
		}	
	}
	
	return symbol;
}



int main(){
	Arithmeticcoding ac;
	ac.requirecode();
	string str;
	cin>>str;
	double encode1=ac.encode(str);
	cout<<encode1<<endl;
	cout<<ac.decode(encode1)<<endl;
	
	return 0;
	
} 

测试数据:

A
0.1
B
0.4
C
0.2
D
0.3
#
CADACDB
0.514388
CADACDB

 

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值