算法原理:(非常清晰)
//门一旦打开就不关闭,是指在一个压缩段内。
说明:该算法的压缩效果和数据有很大关系,一般测试时用正弦波数据,压缩效果很好,如果用随机数,基本不会压缩。
==============================
程序说明:
E(压缩精度)的值要根据待压缩的数值来定,如果E的值太小,解压误差会很小,但压缩率低。
如果E的值太大,压缩比非常高,100MB的文件可能就只有几M,但解压误差非常大。所以E要多试几次取一个比较合理的值。
5.解压过程:(线性插值)有起点和终点坐标可以求出线段的公式,然后根据某点x轴坐标求出其对应的y的值,也就是实际的值。
=====================
#include <stdio.h>
#define MAX_DOUBLE 1.79769e+308
#define E 3
struct point
{
int x, y;
};
void compress()
{
FILE * fin = fopen("rand.txt", "r");
FILE * fout = fopen("out.txt", "w");
//上门和下门,初始时门是关着的
double up_gate = -MAX_DOUBLE;
double down_gate = MAX_DOUBLE;
//当前数据的上斜率和下斜率
double now_up, now_down;
int data; //当前读取到的数据
int last_read_data; //当前数据的前一个数据
int last_stored_data; //最近保存的点
//read and save the first data
fscanf(fin, "%d", &last_stored_data);
fprintf(fout, "0 %d ", last_stored_data);
last_read_data = last_stored_data;
int last_stored_t = 0; //最近保存数据的时间,init 0
//循环处理数据
int t=0;
while(++t, fscanf(fin, "%d", &data) != EOF)
{
now_up = double(data-last_stored_data-E) / (t-last_stored_t);
if(now_up > up_gate)
up_gate = now_up;
now_down = double(data-last_stored_data+E) / (t-last_stored_t);
if(now_down < down_gate)
down_gate = now_down;
if(up_gate >= down_gate)
{
//保存前一个点
fprintf(fout, "%d %d ", t-1, last_read_data);
last_stored_t = t-1; //修改最近保存数据时间点
last_stored_data = last_read_data;
//初始化两扇门为当前点与上个点的斜率
up_gate = double(data-last_stored_data-E);
down_gate = double(data-last_stored_data+E);
}
last_read_data = data;
}
// sava end point
fprintf(fout, "%d %d ", t-1, last_read_data);
fclose(fin);
fclose(fout);
}
void uncompress()
{
FILE * fin = fopen("out.txt", "r");
FILE * fout = fopen("src.txt", "w");
point a,b;
fscanf(fin, "%d %d", &a.x, &a.y);
while(fscanf(fin, "%d %d", &b.x,&b.y) != EOF)
{
//Step.1
fprintf(fout, "%d ", a.y);
//Step.2
if(a.x+1 != b.x)
{
double k = double(b.y - a.y) / (b.x - a.x); //计算斜率
for(int i=a.x+1; i<b.x; i++)
{
//线性插值求被压缩掉的数据
fprintf(fout, "%.0lf ", k*(i-a.x) + a.y);
}
}
a.x = b.x;
a.y = b.y;
}
fprintf(fout, "%d ", b.y);
fclose(fin);
fclose(fout);
}
int main(void)
{
compress();
uncompress();
return 0;
}
其实把current , lastRead, lastStored定义为Point类型程序会更清晰。
下面上一下压缩效果图,界面是用.Net中的Chart控件做的,用法很简单,如果想直观的看到结果,你们可以托一个控件上去看看效果~ 挺好玩的。
上面的曲线是原数据,总共是800个点,压缩后可以看到,储存的点屈指可数。
从图中可以看出对均匀变化的数据压缩效果是非常好的,但是随机数基本上不会被压缩,图就不贴了。