C中矩阵的迭代器和指针

时间:2014-09-21 16:52:31

标签: c pointers matrix iterator

对于JPEG图像压缩,我以灰度级和8位像素操作图像

我有这种动态分配的矩阵:

typedef char pixel_t;
pixel_t ** pix_matrix;

分配并填充后,我有一个二维数组,其中包含图片亮度的值(从-128到+127)。

对于JPEG压缩,我需要像这样以zigzag迭代这个数组:

http://i.stack.imgur.com/BJULt.jpg

所以我想为这种类型创建一个Iterator结构。这个迭代器必须有'current'和'begin'成员,我希望这些成员成为当前元素和矩阵的第一个元素的指针。换句话说,我想存储地址而不是索引。但是经过几个小时的测试,打印和研究,我找不到实现这一目标的方法。我必须使用什么类型的指针?如何让它指向我的矩阵的第一个地址?我的要求是否可能?

如果所有这一切都成为可能,我怎样才能得到下一个元素,以及当前元素的值?

2 个答案:

答案 0 :(得分:0)

您可以编写一个interator结构:

struct zigzag_t {
    int width;      // width, must be initialised
    int height;     // height, must be initialised
    int x;          // current x index
    int y;          // current y index
    int underway;   // dummy value to start at (0, 0)
};

您必须使用图像的宽度和高度进行初始化。编写一个interator函数,以便你可以使用这样的迭代器:

struct zigzag_t zz = {8, 8};

while (zigzag_next(&zz)) {
    printf("(%d, %d)\n", zz.y, zz.x);
}

迭代器本身并不太复杂:如果xy索引的总和是奇数,那么你向西南方向走,直到你到达西边或南边。如果总和是均匀的,你向东北走,直到你撞到北墙或东墙。如果你击中ne或sw边缘,东边和南边优先。访问se边缘后,迭代结束。

因为结构从x开始,y都为零,所以第一个点是(0,1)。为了解决这个问题,使用虚拟域underway,它也是零。

如果要再次使用迭代器,则必须重置它。更好的是,定义并初始化一个新的迭代器。

迭代器函数:

int zigzag_next(struct zigzag_t *zz)
{
    int odd = (zz->x + zz->y) % 2;

    if (zz->underway == 0) {
        zz->x = zz->y = 0;
        zz->underway = 1;
        return 1;
    }

    if (odd) {
        /* walk southwest */

        int w_edge = zz->x == 0;
        int s_edge = zz->y == zz->height - 1;

        if (s_edge) {
            zz->x++;
            return zz->x < zz->width;
        } else if (w_edge) {
            zz->y++;
        } else {
            zz->x--;
            zz->y++;
        }
    } else {
        /* walk northeast */

        int e_edge = zz->x == zz->width - 1;
        int n_edge = zz->y == 0;

        if (e_edge) {
            zz->y++;
            return zz->y < zz->height;
        } else if (n_edge) {
            zz->x++;
        } else {
            zz->x++;
            zz->y--;
        }
    }

    return 1;
}

此解决方案返回x和y位置,您可以将其用作指向像素数据的双指针的索引。扩展结构以保持指向像素数据的基指针并让迭代器函数返回指向像素的指针或NULL如果迭代已经用完就不难了。

带有指针的示例解决方案如下。

#include <stdlib.h>
#include <stdio.h>

typedef char pixel_t;

struct zigzag_t {
    pixel_t **p;    // base data
    int width;      // width, must be initialised
    int height;     // height, must be initialised
    int x;          // current x index
    int y;          // current y index
    int underway;   // dummy value to start at (0, 0)
};

pixel_t *zigzag_next(struct zigzag_t *zz)
{
    int odd = (zz->x + zz->y) % 2;

    if (zz->underway == 0) {
        zz->x = zz->y = 0;
        zz->underway = 1;
        return *zz->p;
    }

    if (odd) {
        /* walk southwest */

        int w_edge = zz->x == 0;
        int s_edge = zz->y == zz->height - 1;

        if (s_edge) {
            zz->x++;
            if (zz->x == zz->width) return NULL;
        } else if (w_edge) {
            zz->y++;
        } else {
            zz->x--;
            zz->y++;
        }
    } else {
        /* walk northeast */

        int e_edge = zz->x == zz->width - 1;
        int n_edge = zz->y == 0;

        if (e_edge) {
            zz->y++;
            if (zz->y == zz->height) return NULL;
        } else if (n_edge) {
            zz->x++;
        } else {
            zz->x++;
            zz->y--;
        }
    }

    return zz->p[zz->y] + zz->x;
}

int main()
{
    pixel_t *data[] = {
        "abcde", "fghij", "klmno", "pqrst", "uvwxy"
    };

    struct zigzag_t zz = {data, 5, 5};

    for (;;) {
        pixel_t *p = zigzag_next(&zz);

        if (p == NULL) break;
        putchar(*p);
    }
    putchar('\n');

    return 0;
}

此解决方案是C解决方案。没有begin成员函数;通过简单的结构初始化完成初始化。没有增量运算符,也没有end成员函数;向前移动迭代器并检查结束是在一个普通的旧函数中完成的。

您已经标记了问题C,但迭代器在C ++中更常见,它们可以作为类实现。上述C示例可以作为此类实现的基础。

答案 1 :(得分:0)

美好而简单。

  • 函数next是迭代器;它返回true,直到访问过所有单元格。
  • 类型POSITION的变量保存迭代器状态。
  • 函数current返回指向矩阵中当前单元格的指针。

演示函数sample_application将所有内容放在一起。

#define MAX_XY 7

typedef struct { int x, y; } POSITION;

static int sign_of(int i)
{
    return i < 0 ? -1 : i > 0 ? 1 : 0;
}

static int get_direction(int a, int b, int odd_is_forward)
{
    return sign_of(((a + b) % 2 == odd_is_forward || b >= MAX_XY ? MAX_XY : 0) - a);
}

int next(POSITION *pos)
{
    int x = pos->x;
    int y = pos->y;
    pos->x += get_direction(x, y, 0);
    pos->y += get_direction(y, x, 1);
    return x < MAX_XY || y < MAX_XY;
}

pixel_t *current(POSITION *pos)
{
    return &pix_matrix[pos->y][pos->x];
}

void sample_application()      // just demonstrating the use of POSITION
{
    POSITION pos = {-1, -1};   // always start from these dummy coordinates
    while (next(&pos))         // this iterates through the matrix
    {
        int coord_x = pos.x;   // this is how you get the current coordinates
        int coord_y = pos.y;
        *current(&pos) = 12;   // this is how you access the current cell
    }
}