将2D变换矩阵转换为1D

6

我有一个问题,需要在C语言中使用函数将2D矩阵传递给1D向量数组。以下是我想要创建的代码:

#include <stdio.h>
#define N  64
#define A  8


int tab2[A][A];
int vect[N];
void fonc(int i,int j,int k,int l,int c,int **tab2,int *vect);

void fonc(int i,int j,int k,int l,int c,int **tab2,int *vect){

vect[k]=tab2[0][0];
printf("%d",vect[k]);
  while(i!=8 && j!=8)
    {
        //bas
        i=i;
    j=j+1;


    vect[k]++;
      printf("%d\t",vect[k]);
    //descente
    while(j !=0)
    {
     i=i+1;
     j=j-1;

     vect[k]++;
    }

    //droite
    i=i;
    j=j+1;

    vect[k]++;
     //montée
    while(i !=0)
    {
     i=i-1;
     j=j+1;

     vect[k]++;
    }
    }

}



int main (){
    int vect[64] ;
int tab2[8][8]={
{1, 2, 6, 7, 15, 16 ,28 ,1},
{3, 5, 8, 14, 17 ,27 ,29 ,1},
{4, 9, 13, 18, 26, 30, 39 ,1},
{10, 12, 19, 25, 31 ,38 ,40 ,1},
{11, 20 ,24, 32 ,37 ,41 ,46 ,1} ,
{21 ,23, 33, 36, 42, 45, 47 ,1},
{22, 34 ,35, 43, 44, 48, 49 ,1},
{22, 34 ,35, 43, 44, 48, 49 ,1}};
    int i;
    int j;
    int k;

fonc(i,j,k,8,8,tab2,vect);
//printf("%d\n", ) ;//limpide !
return 0;
}

我没有错误,但我无法调试并得到结果。有人有想法怎么做吗?我使用函数对JPEG压缩RLE编码应用了一种Zigzag线性变换。

谢谢大家!我尝试做这个:

enter image description here
0, 0
0, 1    1, 0
2, 0    1, 1    0, 2
0, 3    1, 2    2, 1    3, 0
4, 0    3, 1    2, 2    1, 3    0, 4
0, 5    1, 4    2, 3    3, 2    4, 1    5, 0
6, 0    5, 1    4, 2    3, 3    2, 4    1, 5    0, 6
0, 7    1, 6    2, 5    3, 4    4, 3    5, 2    6, 1    7, 0
7, 1    6, 2    5, 3    4, 4    3, 5    2, 6    1, 7
2, 7    3, 6    4, 5    5, 4    6, 3    7, 2

2
你的函数中传递的 i, jk 值是毫无意义的,因此这是未定义行为。它们不应该成为参数,而应该是函数内的本地变量,在任务执行前得到恰当的初始化。 - WhozCraig
12
在别人回答问题后不要试图销毁这个问题,这样做对于那些尝试帮助你的人是不公平的。请记住公平竞争。 - Jonathan Leffler
3
乔纳森是正确的。问题是为了未来的访问者而存在的,而不仅仅是那些提出问题的人。我再次撤销了你破坏性的编辑。如果这种情况再次发生,我将锁定此问题,使其无法进行编辑。 - Brad Larson
5
好的,我已经警告过你了。现在将此锁定。 - Brad Larson
3个回答

15
你的函数有3个不必要的参数 — ijk。传递给函数的值在 main() 中未初始化;函数中传递的 ij 的值是不相关的,因为代码在第一次使用变量时会设置它们的值。k 的值被使用,但传递给函数的值是不确定的。需要更改这些参数,使它们成为函数内部的局部变量,并将其全部设置为零。(k 是向量中下一个矩阵值应该分配的索引;ij 是数组的下标)。
你应该去掉这两个全局变量;它们从未被引用,因为在 main() 中的局部变量隐藏了它们,并且函数的参数也隐藏了它们。两个 #define 值也从未被使用。
虽然你传递了 lc(行和列),但你忽略了它们,并假设上限为 l = 8c = 8。另外,你尝试传递给 fonc 的类型不是 int **tab2,而是 int tab2[][8]int tab2[8][8]。函数签名可以改为:
void fonc(int tab2[8][8], int *vect);

在你的函数中,每个形式为vect[k]++; 的赋值语句都应该改为形式为vect[k++] = tab2[i][j]; 的赋值语句。

实现zig-zag算法很棘手。对于8x8固定大小的矩阵,把索引序列打包进数组是很诱人的。假设zig-zag图形的左上角为(0, 0),右下角为(7, 7)。如果这不对,你只需要修正表格的初始化即可。

static const struct ZigZag
{
    unsigned char y, x;  // Reversed from original
} zigzag[] =
{
    { 0, 0 }, { 1, 0 }, { 0, 1 }, { 0, 2 },
    { 1, 1 }, { 2, 0 }, { 3, 0 }, { 2, 1 },
    { 1, 2 }, { 0, 3 }, { 0, 4 }, { 1, 3 },
    ...
    { 7, 5 }, { 7, 6 }, { 6, 7 }, { 7, 7 },
};

正确的复制操作非常简单:

for (int i = 0; i < 64; i++)
    vect[i] = tab[zigzag[i].x][zigzag[i].y];

我们可以讨论写64与sizeof(zigzag)/sizeof(zigzag[0])的区别。如果你真的很缺内存(目前数据仅为128字节,所以我不相信你),那么你可以将两个坐标压缩成一个字节进行存储:

static const unsigned char zigzag[] =
{
    0x00, 0x10, 0x01, 0x02, ...
};

然后使用更复杂的下标表达式:

vect[i] = tab[zigzag[i] >> 4][zigzag[i] & 0xF];

可能由于内存访问较少而更快 - 需要进行测量。

这一切都假设您正在处理8x8固定大小的正方形数组。 如果您必须处理任何大小的数组并仍要完成工作,则可能必须对事物进行编码,以便指定起始点,向右移动一步,对角线向左下移动,直到达到边缘(左侧或底部),向下或向右移动一步,对角线向右上移动,直到达到边缘(顶部或右侧),向右或向下移动一步,重复直到达到末尾。 编写代码将会比较繁琐;复制循环将不止两行。

来自问题的仪器化代码

这是问题中的代码,有所清理,但 fonc() 中的核心算法未更改 - 至少在处理 ijk 时未更改,除了初始化它们。 主函数在调用 fonc() 之前打印矩阵,之后打印向量。 fonc() 中每次分配给向量的操作均已修复和记录。

#include <stdio.h>

void fonc(int tab2[8][8], int *vect);

void fonc(int tab2[8][8], int *vect)
{
    int i = 0;
    int j = 0;
    int k = 0;

    vect[k] = tab2[i][j];
    printf("v[%2d] = m[%2d][%2d] = %d\n", k, i, j, tab2[i][j]);

    while (i != 8 && j != 8)
    {
        // bas
        i = i;
        j = j+1;
        vect[k++] = tab2[i][j];
        printf("v[%2d] = m[%2d][%2d] = %d\n", k, i, j, tab2[i][j]);

        // descente
        while (j != 0)
        {
            i = i+1;
            j = j-1;
            vect[k++] = tab2[i][j];
            printf("v[%2d] = m[%2d][%2d] = %d\n", k, i, j, tab2[i][j]);
        }

        // droite
        i = i;
        j = j+1;
        vect[k++] = tab2[i][j];
        printf("v[%2d] = m[%2d][%2d] = %d\n", k, i, j, tab2[i][j]);

        // montée
        while (i != 0)
        {
            i = i-1;
            j = j+1;
            printf("v[%2d] = m[%2d][%2d] = %d\n", k, i, j, tab2[i][j]);
            vect[k++] = tab2[i][j];
        }
    }
}

int main(void)
{
    int vect[64];
    int tab2[8][8] =
    {
        // Up to element value 28, the data should appear in
        // the order 1, 2, 3, ... in the output vector
        {1, 2, 6, 7, 15, 16, 28, 1},
        {3, 5, 8, 14, 17, 27, 29, 1},
        {4, 9, 13, 18, 26, 30, 39, 1},
        {10, 12, 19, 25, 31, 38, 40, 1},
        {11, 20, 24, 32, 37, 41, 46, 1},
        {21, 23, 33, 36, 42, 45, 47, 1},
        {22, 34, 35, 43, 44, 48, 49, 1},
        {22, 34, 35, 43, 44, 48, 49, 1}
    };

    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
            printf("%3d", tab2[i][j]);
        putchar('\n');
    }

    fonc(tab2, vect);

    for (int i = 0; i < 8 * 8; i++)
    {
        printf("%3d", vect[i]);
        if (i % 8 == 7)
            putchar('\n');
    }

    return 0;
}

示例输出:

  1  2  6  7 15 16 28  1
  3  5  8 14 17 27 29  1
  4  9 13 18 26 30 39  1
 10 12 19 25 31 38 40  1
 11 20 24 32 37 41 46  1
 21 23 33 36 42 45 47  1
 22 34 35 43 44 48 49  1
 22 34 35 43 44 48 49  1
v[ 0] = m[ 0][ 0] = 1
v[ 1] = m[ 0][ 1] = 2
v[ 2] = m[ 1][ 0] = 3
v[ 3] = m[ 1][ 1] = 5
v[ 3] = m[ 0][ 2] = 6
v[ 5] = m[ 0][ 3] = 7
v[ 6] = m[ 1][ 2] = 8
v[ 7] = m[ 2][ 1] = 9
v[ 8] = m[ 3][ 0] = 10
v[ 9] = m[ 3][ 1] = 12
v[ 9] = m[ 2][ 2] = 13
v[10] = m[ 1][ 3] = 14
v[11] = m[ 0][ 4] = 15
v[13] = m[ 0][ 5] = 16
v[14] = m[ 1][ 4] = 17
v[15] = m[ 2][ 3] = 18
v[16] = m[ 3][ 2] = 19
v[17] = m[ 4][ 1] = 20
v[18] = m[ 5][ 0] = 21
v[19] = m[ 5][ 1] = 23
v[19] = m[ 4][ 2] = 24
v[20] = m[ 3][ 3] = 25
v[21] = m[ 2][ 4] = 26
v[22] = m[ 1][ 5] = 27
v[23] = m[ 0][ 6] = 28
v[25] = m[ 0][ 7] = 1
v[26] = m[ 1][ 6] = 29
v[27] = m[ 2][ 5] = 30
v[28] = m[ 3][ 4] = 31
v[29] = m[ 4][ 3] = 32
v[30] = m[ 5][ 2] = 33
v[31] = m[ 6][ 1] = 34
v[32] = m[ 7][ 0] = 22
v[33] = m[ 7][ 1] = 34
v[33] = m[ 6][ 2] = 35
v[34] = m[ 5][ 3] = 36
v[35] = m[ 4][ 4] = 37
v[36] = m[ 3][ 5] = 38
v[37] = m[ 2][ 6] = 39
v[38] = m[ 1][ 7] = 1
v[39] = m[ 0][ 8] = 3
  2  3  5  6  7  8  9 10
 12 13 14 15 16 17 18 19
 20 21 23 24 25 26 27 28
  1 29 30 31 32 33 34 22
 34 35 36 37 38 39  1  3
  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0
  0  0  0  0  0  0  0  0

注意:

  1. 您访问了越界的 tab2[0][8]
  2. 当您的对角线运动撞到矩阵底部或右侧时,您的算法会遇到问题。
  3. 如果没有C99和VLA支持,处理可变的NxM数组将是一件麻烦的事情。

表驱动程序

#include <stdio.h>

void fonc(int tab2[8][8], int vect[8]);

void fonc(int tab2[8][8], int vect[8])
{
    static const struct ZigZag
    {
        unsigned char y, x;
    } zigzag[8*8] =
    {
        { 0, 0 }, { 1, 0 }, { 0, 1 }, { 0, 2 },
        { 1, 1 }, { 2, 0 }, { 3, 0 }, { 2, 1 },
        { 1, 2 }, { 0, 3 }, { 0, 4 }, { 1, 3 },
        { 2, 2 }, { 3, 1 }, { 4, 0 }, { 5, 0 },
        { 4, 1 }, { 3, 2 }, { 2, 3 }, { 1, 4 },
        { 0, 5 }, { 0, 6 }, { 1, 5 }, { 2, 4 },
        { 3, 3 }, { 4, 2 }, { 5, 1 }, { 6, 0 },
        { 7, 0 }, { 6, 1 }, { 5, 2 }, { 4, 3 },
        { 3, 4 }, { 2, 5 }, { 1, 6 }, { 0, 7 },
        { 1, 7 }, { 2, 6 }, { 3, 5 }, { 4, 4 },
        { 5, 3 }, { 6, 2 }, { 7, 1 }, { 7, 2 },
        { 6, 3 }, { 5, 4 }, { 4, 5 }, { 3, 6 },
        { 2, 7 }, { 3, 7 }, { 4, 6 }, { 5, 5 },
        { 6, 4 }, { 7, 3 }, { 7, 4 }, { 6, 5 },
        { 5, 6 }, { 4, 7 }, { 5, 7 }, { 6, 6 },
        { 7, 5 }, { 7, 6 }, { 6, 7 }, { 7, 7 },
    };

    for (int i = 0; i < 64; i++)
        vect[i] = tab2[zigzag[i].x][zigzag[i].y];
}

// The output vector should be in order 1..64
int main(void)
{
    int vect[64];
    int tab2[8][8] =
    {
        {  1,  2,  6,  7, 15, 16, 28, 29 },
        {  3,  5,  8, 14, 17, 27, 30, 43 },
        {  4,  9, 13, 18, 26, 31, 42, 44 },
        { 10, 12, 19, 25, 32, 41, 45, 54 },
        { 11, 20, 24, 33, 40, 46, 53, 55 },
        { 21, 23, 34, 39, 47, 52, 56, 61 },
        { 22, 35, 38, 48, 51, 57, 60, 62 },
        { 36, 37, 49, 50, 58, 59, 63, 64 }
    };

    puts("Matrix:");
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
            printf("%3d", tab2[i][j]);
        putchar('\n');
    }

    fonc(tab2, vect);

    puts("Vector:");
    for (int i = 0; i < 8 * 8; i++)
    {
        printf("%3d", vect[i]);
        if (i % 8 == 7)
            putchar('\n');
    }

    return 0;
}

示例输出:

Matrix:
  1  2  6  7 15 16 28 29
  3  5  8 14 17 27 30 43
  4  9 13 18 26 31 42 44
 10 12 19 25 32 41 45 54
 11 20 24 33 40 46 53 55
 21 23 34 39 47 52 56 61
 22 35 38 48 51 57 60 62
 36 37 49 50 58 59 63 64
Vector:
  1  2  3  4  5  6  7  8
  9 10 11 12 13 14 15 16
 17 18 19 20 21 22 23 24
 25 26 27 28 29 30 31 32
 33 34 35 36 37 38 39 40
 41 42 43 44 45 46 47 48
 49 50 51 52 53 54 55 56
 57 58 59 60 61 62 63 64

Anonymous编写的代码的检测版

Anonymous提供了一个答案。它在概念上非常有趣,但我不确定它是否准确。为了检测它,使其打印出输入和输出是不够充分的,因此我加入了与上面代码相同的表格,应该产生1..64向量。以下是代码和输出:

#include <stdio.h>

#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) > (b) ? (b) : (a))

void dezigzag(int out[64], int in[8][8])
{
    int n = 0;
    for (int diag = 0; diag < 15; diag++)
    {
        for (int i = max(0, diag - 7); i <= min(7, diag); i++)
            out[n++] = diag % 2 ? in[diag - i][i] : in[i][diag - i];
    }
}

int main(void)
{
    int out[64] = {-1};
    int in[8][8];

    for (int i = 0; i < 64; i++)
        in[i % 8][i / 8] = i;

    puts("Matrix:");
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
            printf("%3d", in[i][j]);
        putchar('\n');
    }

    dezigzag(out, in);

    puts("Vector:");
    for (int i = 0; i < 8 * 8; i++)
    {
        printf("%3d", out[i]);
        if (i % 8 == 7)
            putchar('\n');
    }

    //for (int i = 0; i < 64; i++) {
    //    printf("%d: %d\n", i, out[i]);
    //}

    int tab2[8][8] =
    {
        {  1,  2,  6,  7, 15, 16, 28, 29 },
        {  3,  5,  8, 14, 17, 27, 30, 43 },
        {  4,  9, 13, 18, 26, 31, 42, 44 },
        { 10, 12, 19, 25, 32, 41, 45, 54 },
        { 11, 20, 24, 33, 40, 46, 53, 55 },
        { 21, 23, 34, 39, 47, 52, 56, 61 },
        { 22, 35, 38, 48, 51, 57, 60, 62 },
        { 36, 37, 49, 50, 58, 59, 63, 64 },
    };

    puts("Matrix:");
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
            printf("%3d", tab2[i][j]);
        putchar('\n');
    }

    dezigzag(out, tab2);

    puts("Vector:");
    for (int i = 0; i < 8 * 8; i++)
    {
        printf("%3d", out[i]);
        if (i % 8 == 7)
            putchar('\n');
    }

    return 0;
}

输出:

Matrix:
  0  8 16 24 32 40 48 56
  1  9 17 25 33 41 49 57
  2 10 18 26 34 42 50 58
  3 11 19 27 35 43 51 59
  4 12 20 28 36 44 52 60
  5 13 21 29 37 45 53 61
  6 14 22 30 38 46 54 62
  7 15 23 31 39 47 55 63
Vector:
  0  1  8 16  9  2  3 10
 17 24 32 25 18 11  4  5
 12 19 26 33 40 48 41 34
 27 20 13  6  7 14 21 28
 35 42 49 56 57 50 43 36
 29 22 15 23 30 37 44 51
 58 59 52 45 38 31 39 46
 53 60 61 54 47 55 62 63
Matrix:
  1  2  6  7 15 16 28 29
  3  5  8 14 17 27 30 43
  4  9 13 18 26 31 42 44
 10 12 19 25 32 41 45 54
 11 20 24 33 40 46 53 55
 21 23 34 39 47 52 56 61
 22 35 38 48 51 57 60 62
 36 37 49 50 58 59 63 64
Vector:
  1  3  2  6  5  4 10  9
  8  7 15 14 13 12 11 21
 20 19 18 17 16 28 27 26
 25 24 23 22 36 35 34 33
 32 31 30 29 43 42 41 40
 39 38 37 49 48 47 46 45
 44 54 53 52 51 50 58 57
 56 55 61 60 59 63 62 64

这个结果不完全正确,但我相信它是正确的方向。(同样明显的是,这个问题太复杂了,无法在对匿名用户的评论中进行解释-因此在这里进行补充。)

从概念上讲,代码将正方形矩阵旋转,使其立在其点上,然后水平来回扫描(8 + 8-1)条线。

3x3扫描的ASCII艺术:

   /\
  /\/\
 /\/\/\
 \/\/\/
  \/\/
   \/

共有(3 + 3 - 1) = 5个扫描行。在表驱动代码中,数据具有与此对应的规律。

要修复匿名者的代码

在函数dezigzag()中,赋值行需要反转条件。现有代码相当于:

out[n++] = (diag % 2 == 1) ? in[diag - i][i] : in[i][diag - i];

正确的代码是:

out[n++] = (diag % 2 == 0) ? in[diag - i][i] : in[i][diag - i];
输出结果如下:
Matrix:
  0  8 16 24 32 40 48 56
  1  9 17 25 33 41 49 57
  2 10 18 26 34 42 50 58
  3 11 19 27 35 43 51 59
  4 12 20 28 36 44 52 60
  5 13 21 29 37 45 53 61
  6 14 22 30 38 46 54 62
  7 15 23 31 39 47 55 63
Vector:
  0  8  1  2  9 16 24 17
 10  3  4 11 18 25 32 40
 33 26 19 12  5  6 13 20
 27 34 41 48 56 49 42 35
 28 21 14  7 15 22 29 36
 43 50 57 58 51 44 37 30
 23 31 38 45 52 59 60 53
 46 39 47 54 61 62 55 63
Matrix:
  1  2  6  7 15 16 28 29
  3  5  8 14 17 27 30 43
  4  9 13 18 26 31 42 44
 10 12 19 25 32 41 45 54
 11 20 24 33 40 46 53 55
 21 23 34 39 47 52 56 61
 22 35 38 48 51 57 60 62
 36 37 49 50 58 59 63 64
Vector:
  1  2  3  4  5  6  7  8
  9 10 11 12 13 14 15 16
 17 18 19 20 21 22 23 24
 25 26 27 28 29 30 31 32
 33 34 35 36 37 38 39 40
 41 42 43 44 45 46 47 48
 49 50 51 52 53 54 55 56
 57 58 59 60 61 62 63 64

处理MxN数组的代码

#include <stdio.h>

static inline int max(int a, int b) { return (a > b) ? a : b; }
static inline int min(int a, int b) { return (a < b) ? a : b; }

static void print_info(int rows, int cols)
{
    int n = rows + cols - 1;
    printf("R = %d, C = %d, N = %d\n", rows, cols, n);
    for (int i = 0; i < n; i++)
    {
        int max_x = min(i, cols-1);
        int min_x = max(0, i - n + cols);
        int max_y = min(i, rows-1);
        int min_y = max(0, i - n + rows);
        printf("i = %d, min_x = %d, max_x = %d, min_y = %d, max_y = %d\n",
                i, min_x, max_x, min_y, max_y);
    }

    for (int i = 0; i < n; i++)
    {
        printf("%2d:", i);
        if (i % 2 == 0)
        {
            int max_x = min(i, cols-1);
            int min_x = max(0, i - n + cols);
            for (int j = min_x; j <= max_x; j++)
                /* (row,col) */
                printf(" (r=%d,c=%d)", i - j, j);
        }
        else
        {
            int max_y = min(i, rows-1);
            int min_y = max(0, i - n + rows);
            for (int j = min_y; j <= max_y; j++)
                printf(" (r=%d,c=%d)", j, i - j);
        }
        putchar('\n');
    }
}

static void set_zigzag(int rows, int cols, int matrix[rows][cols])
{
    int x = 0;
    int n = rows + cols - 1;
    for (int i = 0; i < n; i++)
    {
        if (i % 2 == 0)
        {
            int max_x = min(i, cols-1);
            int min_x = max(0, i - n + cols);
            for (int j = min_x; j <= max_x; j++)
                matrix[i-j][j] = x++;
        }
        else
        {
            int max_y = min(i, rows-1);
            int min_y = max(0, i - n + rows);
            for (int j = min_y; j <= max_y; j++)
                matrix[j][i-j] = x++;
        }
    }
}

static void zigzag(int rows, int cols, int matrix[rows][cols], int vector[rows*cols])
{
    int n = rows + cols - 1;
    int v = 0;
    for (int i = 0; i < n; i++)
    {
        if (i % 2 == 0)
        {
            int max_x = min(i, cols-1);
            int min_x = max(0, i - n + cols);
            for (int j = min_x; j <= max_x; j++)
                vector[v++] = matrix[i-j][j];
        }
        else
        {
            int max_y = min(i, rows-1);
            int min_y = max(0, i - n + rows);
            for (int j = min_y; j <= max_y; j++)
                vector[v++] = matrix[j][i-j];
        }
    }
}

static void dump_matrix(const char *tag, int rows, int cols, int matrix[rows][cols])
{
    printf("%s (%d x %d):\n", tag, rows, cols);
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
            printf("%3d", matrix[i][j]);
        putchar('\n');
    }
}

static void dump_vector(const char *tag, int rows, int cols, int vector[rows * cols])
{
    printf("%s (%d : %d):\n", tag, rows, cols);
    for (int i = 0; i < rows * cols; i++)
    {
        printf("%3d", vector[i]);
        if (i % cols == cols - 1)
            putchar('\n');
    }
}

static void test_rows_x_cols(int rows, int cols)
{
    int vector[rows * cols];
    int matrix[rows][cols];

    printf("\nTest %dx%d\n\n", rows, cols);
    print_info(rows, cols);
    set_zigzag(rows, cols, matrix);
    dump_matrix("Matrix", rows, cols, matrix);
    zigzag(rows, cols, matrix, vector);
    dump_vector("Vector", rows, cols, vector);
}

int main(void)
{
    struct
    {
        int rows;
        int cols;
    } test[] =
    {
        { 4, 4 }, { 6, 4 }, { 4, 7 }, { 7, 14 }, { 6, 16 }, { 3, 33 },
    };
    enum { NUM_TEST = sizeof(test) / sizeof(test[0]) };

    for (int i = 0; i < NUM_TEST; i++)
        test_rows_x_cols(test[i].rows, test[i].cols);

    return 0;
}

使用迭代器结构的代码

迭代器结构相当复杂。使用多个单行内联函数是极端的,但避免了重复表达式。我相信有整理的空间,但是现在是停止享乐的时候了。

#include <assert.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>

typedef struct RC
{
    int row;
    int col;
} RC;

typedef struct RLE
{
    RC  curr;
    RC  size;
    int zigzag;
    int sequence;
} RLE;

static inline int max(int a, int b) { return (a > b) ? a : b; }
static inline int min(int a, int b) { return (a < b) ? a : b; }

static inline int get_num_zigzags(const RLE *rle)
{
    return rle->size.row + rle->size.col - 1;
}

static inline int get_max_row(const RLE *rle)
{
    return min(rle->zigzag, rle->size.row - 1);
}

static inline int get_min_row(const RLE *rle)
{
    return max(0, rle->zigzag - get_num_zigzags(rle) + rle->size.row);
}

static inline int get_max_col(const RLE *rle)
{
    return min(rle->zigzag, rle->size.col - 1);
}

static inline int get_min_col(const RLE *rle)
{
    return max(0, rle->zigzag - get_num_zigzags(rle) + rle->size.col);
}

static inline int get_row_from_col(const RLE *rle)
{
    return rle->zigzag - rle->curr.col;
}

static inline int get_col_from_row(const RLE *rle)
{
    return rle->zigzag - rle->curr.row;
}

static RLE RLE_init(int rows, int cols)
{
    RLE rle;
    assert(rows > 0 && cols > 0);
    assert(INT_MAX / rows >= cols);
    rle.curr.row = 0;
    rle.curr.col = 0;
    rle.size.row = rows;
    rle.size.col = cols;
    rle.zigzag = 0;
    rle.sequence = 0;
    return(rle);
}

static inline RC RLE_position(const RLE *rle)
{
    return rle->curr;
}

static inline int RLE_row(const RLE *rle)
{
    return rle->curr.row;
}

static inline int RLE_col(const RLE *rle)
{
    return rle->curr.col;
}

static inline int RLE_sequence(const RLE *rle)
{
    return rle->sequence;
}

static inline int RLE_zigzag(const RLE *rle)
{
    return rle->zigzag;
}

static inline RC RLE_size(const RLE *rle)
{
    return rle->size;
}

static inline bool RLE_finished(const RLE *rle)
{
    return(rle->sequence == rle->size.row * rle->size.col);
}

static void RLE_check(const RLE *rle)
{
    assert(rle->size.row > 0);
    assert(rle->size.col > 0);
    assert(rle->curr.row < rle->size.row && rle->curr.row >= 0);
    assert(rle->curr.col < rle->size.col && rle->curr.col >= 0);
    assert(rle->zigzag >= 0 && rle->zigzag < rle->size.row + rle->size.col - 1);
    assert(rle->sequence >= 0 && rle->sequence <= rle->size.row * rle->size.col);
}

#if defined(REL_DUMP_REQUIRED)
static void RLE_dump(const char *tag, const RLE *rle)
{
    printf("Dump RLE (%s):", tag);
    RC size = RLE_size(rle);
    assert(size.row == rle->size.row);
    assert(size.col == rle->size.col);
    printf("    Rows = %2d, Cols = %2d, Zigzags = %2d; ",
           rle->size.row, rle->size.col, rle->size.row + rle->size.col - 1);
    RC posn = RLE_position(rle);
    assert(posn.row == rle->curr.row);
    assert(posn.col == rle->curr.col);
    assert(posn.row == RLE_row(rle));
    assert(posn.col == RLE_col(rle));
    printf(" Position: r = %d, c = %d; ", RLE_row(rle), RLE_col(rle));
    assert(RLE_zigzag(rle) == rle->zigzag);
    assert(RLE_sequence(rle) == rle->sequence);
    printf(" Zigzag = %d, Sequence = %d\n", rle->zigzag, rle->sequence);
    RLE_check(rle);
}
#endif

static void RLE_next(RLE *rle)
{
    RLE_check(rle);

    /* Already finished? */
    if (RLE_finished(rle))
        return;
    rle->sequence++;
    /* Finished now? */
    if (RLE_finished(rle))
        return;

    if (rle->zigzag % 2 == 0)
    {
        if (rle->curr.col < get_max_col(rle))
        {
            /* Same zigzag */
            rle->curr.col++;
            rle->curr.row = get_row_from_col(rle);
        }
        else
        {
            /* Next zigzag */
            rle->zigzag++;
            rle->curr.row = get_min_row(rle);
            rle->curr.col = get_col_from_row(rle);
        }
    }
    else
    {
        if (rle->curr.row < get_max_row(rle))
        {
            /* Same zigzag */
            rle->curr.row++;
            rle->curr.col = get_col_from_row(rle);
        }
        else
        {
            /* Next zigzag */
            rle->zigzag++;
            rle->curr.col = get_min_col(rle);
            rle->curr.row = get_row_from_col(rle);
        }
    }
}

static void print_info(int rows, int cols)
{
    int n = rows + cols - 1;
    printf("R = %d, C = %d, N = %d\n", rows, cols, n);

    for (int zigzag = 0; zigzag < n; zigzag++)
    {
        int max_col = min(zigzag, cols-1);
        int min_col = max(0, zigzag - n + cols);
        int max_row = min(zigzag, rows-1);
        int min_row = max(0, zigzag - n + rows);
        printf("zigzag = %2d, min_col = %2d, max_col = %2d, min_row = %2d, max_row = %2d\n",
                zigzag, min_col, max_col, min_row, max_row);
    }

    for (int zigzag = 0; zigzag < n; zigzag++)
    {
        printf("%d:", zigzag);
        if (zigzag % 2 == 0)
        {
            int max_col = min(zigzag, cols-1);
            int min_col = max(0, zigzag - n + cols);
            for (int col = min_col; col <= max_col; col++)
                /* (row,col) */
                printf(" (r=%d,c=%d)", zigzag - col, col);
        }
        else
        {
            int max_row = min(zigzag, rows-1);
            int min_row = max(0, zigzag - n + rows);
            for (int row = min_row; row <= max_row; row++)
                printf(" (r=%d,c=%d)", row, zigzag - row);
        }
        putchar('\n');
    }
}

static void dump_matrix(const char *tag, int rows, int cols, int matrix[rows][cols])
{
    printf("%s (%d x %d):\n", tag, rows, cols);
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
            printf("%3d", matrix[i][j]);
        putchar('\n');
    }
}

static void dump_vector(const char *tag, int rows, int cols, int vector[rows * cols])
{
    printf("%s (%d : %d):\n", tag, rows, cols);
    for (int i = 0; i < rows * cols; i++)
    {
        printf("%3d", vector[i]);
        if (i % cols == cols - 1)
            putchar('\n');
    }
}

static void RLE_demonstration(int rows, int cols)
{
    int matrix[rows][cols];
    int vector[rows*cols];

    /* Set matrix */
    for (RLE rle = RLE_init(rows, cols); !RLE_finished(&rle); RLE_next(&rle))
    {
        //RLE_dump("Set Matrix", &rle);
        RC rc = RLE_position(&rle); 
        matrix[rc.row][rc.col] = RLE_sequence(&rle);
    }
    dump_matrix("Matrix", rows, cols, matrix);

    /* Convert matrix to vector */
    for (RLE rle = RLE_init(rows, cols); !RLE_finished(&rle); RLE_next(&rle))
    {
        //RLE_dump("Get Matrix", &rle);
        RC rc = RLE_position(&rle); 
        vector[RLE_sequence(&rle)] = matrix[rc.row][rc.col];
    }
    dump_vector("Vector", rows, cols, vector);
}

int main(int argc, char **argv)
{
    struct
    {
        int rows;
        int cols;
    } test[] =
    {
        { 4, 4 }, { 6, 4 },  { 4, 7 }, { 7, 14 }, { 6, 16 }, { 3, 33 },
    };
    enum { NUM_TEST = sizeof(test) / sizeof(test[0]) };

    /* argv != 0 avoids unused variable warning */
    int verbose = (argv != 0 && argc > 1) ? 1 : 0;

    for (int i = 0; i < NUM_TEST; i++)
    {
        if (verbose)
            print_info(test[i].rows, test[i].cols);
        RLE_demonstration(test[i].rows, test[i].cols);
    }

    return 0;
}

1
好的...你学过结构体吗?如果没有,那么用于保存数据的符号将会让你感到困惑。但这并不难——它可以导致一个紧凑的算法。你需要快速总结一下你所学的内容;位运算是否容易理解? - Jonathan Leffler
是的,我知道结构体。 - Butterflay
“'it is not correct' 是什么意思?你是指你需要一般的算法吗?我写的代码对于你展示的特定的 8x8 情况是正确的,或者说至少可以很容易地变得正确。但是,我已经说过了,它并没有针对 NxM 矩阵进行泛化。” - Jonathan Leffler
1
数据的初始化是可替换的——你想要按照(y, x)的顺序而不是我展示的(x, y)来获取坐标。没问题——你可以轻松地解决这个问题。也许应该用行和列(或线和列)来表示。由于你的之字形图表没有说明matrix[0][0]在哪里(左上角还是左下角),或者你的数据是按行-列还是列-行存储的,因此有很多解释的余地。对于8x8序列的查找表的概念对我来说似乎非常简单,如果大小真的固定,那么它将是最简单的方法。 - Jonathan Leffler
8
注意:这些评论是回答原帖提出的问题的。 - Jonathan Leffler
12
@JonathanLeffler 这有点有趣,试着从答案中推断问题,就像听一方电话那样 :) - Cor_Blimey

6
这是如何用少了17倍行数的方式来实现它:
#define N 8

int mat2d[N][N] = { /* stuff */ };
int vec1d[N * N];
memcpy(vec1d, mat2d, sizeof vec1d);

1
@Butterflay 我想说的是你不需要那么多代码。2D数组在内存中是连续的,就像1D数组一样。 - user529758
2
@Butterflay 因为 (a) 它能够正常工作,(b) 它非常高效,(c) 它只需要三行代码而不是50多行。 - WhozCraig
3
@WhozCraig 我在回答中提到的"17倍少"是认真的,而非讽刺:OP的代码总共有69行。;-) - user529758
1
@H2CO3 我知道,我也没有讽刺的意思。不幸的是,这不是她需要的答案。看起来她想要一个转换。 - WhozCraig
2
@Butterflay,那么你想要的很简单,不需要过分复杂化(我强烈怀疑这是你在这段代码中遇到的最大问题)。我会尽快尝试编写一个更易读的示例。 - user529758
显示剩余8条评论

1

沿着正方形的对角线迭代,每次交替改变方向。

这是一个完整的、可工作的示例(使用c99编写)。

#include <stdio.h>

#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) > (b) ? (b) : (a))

void dezigzag(int out[64], int in[8][8]) {
    int n = 0;
    for (int diag = 0; diag < 15; diag++) {
        for (int i = max(0, diag - 7); i <= min(7, diag); i++) {
            out[n++] = diag % 2 ? in[diag - i][i] : in[i][diag - i];
        }
    }
}

int main(int argc, char *argv[]) {
    int out[64] = {-1};
    int in[8][8];
    for (int i = 0; i < 64; i++) {
        in[i % 8][i / 8] = i;
    }
    dezigzag(out, in);
    for (int i = 0; i < 64; i++) {
        printf("%d: %d\n", i, out[i]);
    }
    return 0;
}

在C99中,使用static inline int max(int a, int b) { return (a > b) ? a : b; }可能更加简洁,当然对于min()也是如此。 - Jonathan Leffler
我喜欢这段代码背后的想法,但还有一些实现细节需要澄清。请参见我的答案附录。 - Jonathan Leffler
事实上,要修正代码,你需要将dezigzag()函数中的条件从当前的diag % 2(相当于diag % 2 == 1)修改为diag % 2 == 0。这样修改后,代码将非常有效地运行。 - Jonathan Leffler
我认为这取决于你如何考虑8x8矩阵的坐标系,无论你是否认为这段代码是正确的。 我假设(i,j)表示第i行,第j列,这是常规数学符号(尽管从零开始索引)。 - Paul Hankin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接