View on GitHub

Yoy-wiw

A website on lisp.

Download this project as a .zip file Download this project as a tar.gz file

Zig-Zag编码及解码

Zig-Zag编码及解码的一个方法。

27 Nov 2013

Zig-zag是一种蛇形编码,把一个矩阵转化为另一个矩阵,矩阵的行列相等。例如:

A B C D           A B E I
E F G H    ==>    F C D G
I J K L    <==    J M N K
M N O P           H L O P

经过分析发现,编码后的行列与编码前的行列有对应关系,这种对应关系是有规律的。

行:0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3
列:0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3
转变为:
行:0 0 1 2 1 0 0 1 2 3 3 2 1 2 3 3 
列:0 1 0 0 1 2 3 2 1 0 1 2 3 3 2 3 

发现转换后的行和列的队列是有规律的,所以可以写个程序构造这个队列。不难看出,第一个元素和最后一个元素与原矩阵相同,所以构造队列要从两头开始,中间汇合。

从第一个元素开始正向构造,然后从最后一个元素开始反向构造。接头的地方就是矩阵的对角线的下方。

 1 static void make_queue(int init, int *queue, int len)
 2 {
 3   int i, tmp;
 4   int loop = init;
 5 
 6   i = 1;
 7   while(1){
 8     tmp = loop;
 9     while(loop > 0){
10       queue[i]=queue[i-1]+1;
11       if(++i >= len){return;}
12       loop-- ;
13     }
14     while(loop < tmp){
15       queue[i]=queue[i-1]-1;
16       if(++i >= len){return;}
17       loop++;
18     }
19     queue[i]=queue[i-1];
20     if(++i >= len){return;}
21 
22     loop += 2;
23   }
24 }
25 static void make_queue_backword(int init, int *queue, int start, int len)
26 {
27   int i, tmp;
28   int loop = init;
29 
30   i = len-2;
31   while(1){
32     tmp = loop;
33     while(loop > 0){
34       queue[i]=queue[i+1]-1;
35       if(--i < start){return;}
36       loop-- ;
37     }
38     while(loop < tmp){
39       queue[i]=queue[i+1]+1;
40       if(--i < start){return;}
41       loop++;
42     }
43     queue[i]=queue[i+1];
44     if(--i < start){return;}
45     loop += 2;
46   }
47 }

构造好两个队列后就可以编码解码了,其实编码解码的过程差不多。解码就是把下标反映射回去。

 1 static void zig_zag(int *dest, int *src, unsigned int d, int decode)
 2 { 
 3   unsigned int m, i;
 4   unsigned int n = d*d;
 5   int * row_queue = malloc(sizeof(int)*n);
 6   int * col_queue = malloc(sizeof(int)*n);
 7 
 8   m = 0;
 9   for(i=1; i<=d; i++){
10     m += i;
11   }
12   row_queue[0]=col_queue[0]=0;
13   make_queue(0, row_queue, m);
14   make_queue(1, col_queue, m);
15 
16   row_queue[n-1]=col_queue[n-1]=d-1;
17   make_queue_backword(0, row_queue, m, n);
18   make_queue_backword(1, col_queue, m, n);
19 
20   if(decode){
21     for(m=0; m<n; m++){
22       dest[row_queue[m]*d+col_queue[m]] = src[m];
23     }
24   }else{
25     for(m=0; m<n; m++){
26       dest[m]=src[row_queue[m]*d+col_queue[m]];
27     }
28   }
29 
30   free(row_queue);
31   free(col_queue);
32 }

好了,测试一下:

 1 static void zig_zag_test_print_matrix(int *q, int d)
 2 {
 3   int i,j;
 4   for(i=0;i<d;i++){
 5     for(j=0; j<d; j++){
 6       fprintf(stdout, "%2d ", q[i*d+j]);
 7     }
 8     fprintf(stdout, "\n");
 9   }
10 }
11 static void zig_zag_test()
12 {
13   int q[16]={0};
14   int p[16];
15   int i;
16   int d = 4;
17   int n = d*d;
18   int m;
19 
20   m = 0;
21   for(i=1; i<=d; i++){
22     m += i;
23   }
24   for(i=0;i<n;i++){
25     p[i]=i;
26   }
27 
28   q[n-1]=d-1;
29   q[0]=0;
30   make_queue(0, q, m);
31   make_queue_backword(0, q, m, n);
32   for(i=0;i<n;i++){
33     fprintf(stdout, "%d ", q[i]);
34   }
35   fprintf(stdout, "\n");
36   make_queue(1, q, m);
37   make_queue_backword(1, q, m, n);
38   for(i=0;i<n;i++){
39     fprintf(stdout, "%d ", q[i]);
40   }
41   fprintf(stdout, "\n");
42 
43   zig_zag(q, p, d, 0);
44   zig_zag_test_print_matrix(q, d);
45   fprintf(stdout, "==============\n");
46   memcpy(p, q, sizeof(p));
47   zig_zag(q, p, d, 1);
48   zig_zag_test_print_matrix(q, d);
49 }
50 int main()
51 {
52    zig_zag_test();
53    return 0;
54 }

方法有点笨,空间复杂性比较高,不知道有没有更好的方法。