算法原理:(非常清晰)
//门一旦打开就不关闭,是指在一个压缩段内。
说明:该算法的压缩效果和数据有很大关系,一般测试时用正弦波数据,压缩效果很好,如果用随机数,基本不会压缩。
==============================
程序说明:
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个点,压缩后可以看到,储存的点屈指可数。
从图中可以看出对均匀变化的数据压缩效果是非常好的,但是随机数基本上不会被压缩,图就不贴了。