简体   繁体   中英

Compare two 2D arrays in C

I have problem comparing two 2D arrays.

Example:

First array:
xxooo
oxxoo
oxooo
oxooo
ooooo

Second array (can be rotated):
oxoo
xxxx
xooo

But when I compare them, I manage to rotate and check similarities for starting left top with two for loops like this:

firstArr[i][j] == secArr[i][j]

How can I check for similarities in whole first array if its dimensions are larger than the second array?

Another example:

在此处输入图片说明

Here is my code:

#include <stdio.h>

int main()
{
    int i, j, pr, ps, pn, r, s;
    int indx = 0, indy = 0, brx = 0, bry = 0;
    int nema = 0;

    scanf(" %d %d %d %d", &r, &s, &pr, &ps);

    char prtljaga[r][s];
    char opredmet[pr][ps], opt1[pr][ps], opt2[ps][pr], opt3[ps][pr];
    int temp[r][s];

    for(i = 0; i < r; i++){
        for(j = 0; j < s; j++){
            temp[i][j] = 0;
        }
    }

    for(i = 0; i < r; i++){
        for(j = 0; j < s; j++){
            scanf(" %c", &prtljaga[i][j]);
        }
    }

    scanf(" %d", &pn);

    while(pn != 0){
        for(i = 0; i < pr; i++){
            for(j = 0; j < ps; j++){
                scanf(" %c", &opredmet[i][j]);
            }
        }

        for(i = 0; i < pr; i++){
            for(j = 0; j < ps; j++){
                opt1[pr-1-i][j] = opredmet[i][j];
            }
        }

        for(i = 0; i < pr; i++){
            for(j = 0; j < ps; j++){
                opt2[j][pr-1-i] = opredmet[i][j];
            }
        }

        for(i = 0; i < pr; i++){
            for(j = 0; j < ps; j++){
                opt3[ps-1-j][i] = opredmet[i][j];
            }
        }

        /* while */
        for(i = 0; i < r; i++){
            for(j = 0; j < s; j++){
                if(j > pr){
                    break;
                }else{
                    if(prtljaga[i][j] == opredmet[i][j]){
                        temp[i][j] = 1;
                    }else{

                    }
                }
            }
        }

        indx = 0; indy = 0; brx = 0; bry = 0;
        for(i = 0; i < r; i++){
            for(j = 0; j < s; j++){
                if(temp[i][j] == 1){
                    brx++;
                    if(brx == 1){
                        indx = j;
                        indy = i;
                    }
                }else{
                    if(brx != pr){
                         brx = 0;
                    }
                }
            }

            if(brx == pr){
                bry++;

                if(bry != pr){
                     brx = 0;
                }
            }else{
                if(bry != ps){
                    bry = 0;
                }
            }

            if(brx == pr && bry == ps){
                printf("%d: [%d, %d]", pn, indx+1, indy+1);
                nema = 1;
                break;
            }
        }

        for(i = 0; i < r; i++){
            for(j = 0; j < s; j++){
                temp[i][j] = 0;
            }
        }
        /* while */

        /* while */
        for(i = 0; i < r; i++){
            for(j = 0; j < s; j++){
                if(j > pr){
                    break;
                }else{
                    if(prtljaga[i][j] == opt1[i][j]){
                        temp[i][j] = 1;
                    }else{

                    }
                }
            }
        }

        for(i = 0; i < r; i++){
            for(j = 0; j < s; j++){
                printf("%d", temp[i][j]);
            }
            printf("\n");
        }

        indx = 0; indy = 0; brx = 0; bry = 0;
        for(i = 0; i < r; i++){
            for(j = 0; j < s; j++){
                if(temp[i][j] == 1){
                    brx++;
                    if(brx == 1 && bry == 0){
                        indx = j;
                        indy = i;
                    }
                }else{
                    if(brx != pr){
                         brx = 0;
                    }
                }
            }

            if(brx == pr){
                bry++;

                if(bry != ps){
                    brx = 0;
                }
            }else{
               if(bry != ps){
                    bry = 0;
                }
            }

            if(brx == pr && bry == ps){
                printf("%d: [%d, %d]", pn, indx+1, indy+1);
                nema = 1;
                break;
            }
        }

        if(nema == 0){
            for(i = 0; i < r; i++){
                for(j = 0; j < s; j++){
                    temp[i][j] = 0;
                }
            }
        }

        for(i = 0; i < r; i++){
            for(j = 0; j < s; j++){
                temp[i][j] = 0;
            }
        }
        /* while */

        /* while */
        for(i = 0; i < r; i++){
            for(j = 0; j < s; j++){
                if(j > pr){
                    break;
                }else{
                    if(prtljaga[i][j] == opt2[i][j]){
                        temp[i][j] = 1;
                    }else{

                    }
                }
            }
        }

        indx = 0; indy = 0; brx = 0; bry = 0;
        for(i = 0; i < r; i++){
            for(j = 0; j < s; j++){
                if(temp[i][j] == 1){
                    brx++;
                    if(brx == 1 && bry == 0){
                        indx = j;
                        indy = i;
                    }
                }else{
                    if(brx != ps){
                         brx = 0;
                    }
                }
            }

            if(brx == ps){
                bry++;

                if(bry != pr){
                     brx = 0;
                }
            }else{
                if(bry != pr){
                    bry = 0;
                }
            }

            if(brx == ps && bry == pr){
                printf("%d: [%d, %d]", pn, indx+1, indy+1);
                nema = 1;
                break;
            }
        }

        for(i = 0; i < r; i++){
            for(j = 0; j < s; j++){
                temp[i][j] = 0;
            }
        }

        for(i = 0; i < r; i++){
            for(j = 0; j < s; j++){
                if(j > pr){
                    break;
                }else{
                    if(prtljaga[i][j] == opt3[i][j]){
                        temp[i][j] = 1;
                    }else{

                    }
                }
            }
        }

        indx = 0; indy = 0; brx = 0; bry = 0;
        for(i = 0; i < r; i++){
            for(j = 0; j < s; j++){
                if(temp[i][j] == 1){
                    brx++;
                    if(brx == 1 && bry == 0){
                        indx = j;
                        indy = i;
                    }
                }else{
                    if(brx != ps){
                         brx = 0;
                    }
                }
            }

            if(brx == ps){
                bry++;

                if(bry != pr){
                     brx = 0;
                }
            }else{
                if(bry != pr){
                    bry = 0;
                }
            }

            if(brx == ps && bry == pr){
                printf("%d: [%d, %d]", pn, indx+1, indy+1);
                nema = 1;
                break;
            }
        }

        for(i = 0; i < r; i++){
            for(j = 0; j < s; j++){
                temp[i][j] = 0;
            }
        }

        indx = 0, indy = 0, brx = 0, bry = 0; pn--;
    }

    if(nema == 0){
        printf("-1");
    }
    return 0;
}

I won't bother with getting into the very large program that was posted, other than to note that you should always check values returned from functions which return meaningful values. The scanf() family of function return meaningful values, which should be checked to help verify whether input is as expected. In the posted code, if the user enters non-numeric input (accidentally or on purpose), the code continues with indeterminate values as if nothing was wrong, leading to potential undefined behavior.

One strategy for checking the larger array against a smaller pattern is to copy smaller regions of interest to a temporary array of the same dimensions as the pattern. This temporary array can be compared with the pattern using memcmp() . Various transformations can be applied to the temporary array, which can then be checked against the pattern again.

Here is an example program using some of the sample input from the question post. The contains_similar() function returns 1 if a match is found, 0 of no match is found. A couple of alternatives would be to return the (upper-left) indices of the first matching pattern, or to store all such indices in an array. There is a reverse_rows() function as an example transformation. This transformation is applied to the temporary array within contains_similar() if the first comparison fails to match, and the transformed region is then compared with the pattern again. A more sophisticated version of this would use an array of pointers to transformation functions which could be iterated over in a comparison loop.

#include <stdio.h>
#include <string.h>

int contains_similar(size_t rows,
                     size_t cols,
                     char arr[rows][cols],
                     size_t prows,
                     size_t pcols,
                     char pat[prows][pcols]);

void reverse_rows(size_t rows, size_t cols, char arr[rows][cols]);
void print_array(size_t rows, size_t cols, char arr[rows][cols]);

int main(void)
{
    char array[][10] = {
        { 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o' },
        { 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o' },
        { 'o', 'o', 'x', 'o', 'o', 'o', 'x', 'o', 'o', 'o' },
        { 'o', 'o', 'x', 'x', 'x', 'x', 'x', 'o', 'o', 'x' },
        { 'o', 'x', 'x', 'o', 'o', 'o', 'o', 'o', 'o', 'x' },
        { 'o', 'x', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'x' },
        { 'o', 'x', 'x', 'o', 'x', 'x', 'o', 'o', 'o', 'x' },
        { 'o', 'o', 'x', 'o', 'x', 'o', 'o', 'o', 'x', 'x' },
        { 'o', 'x', 'x', 'o', 'x', 'o', 'o', 'o', 'o', 'o' },
        { 'o', 'o', 'o', 'o', 'x', 'x', 'x', 'x', 'x', 'o' }
    };

    char pattern[][5] = {
        { 'x', 'x', 'x', 'x', 'x' },
        { 'x', 'o', 'o', 'o', 'x' }
    };

    size_t arr_cols = sizeof array[0];
    size_t arr_rows = sizeof array / arr_cols;
    size_t pat_cols = sizeof pattern[0];
    size_t pat_rows = sizeof pattern / pat_cols;

    printf("Working with %zu X %zu array:\n", arr_rows, arr_cols);
    putchar('\n');
    print_array(arr_rows, arr_cols, array);

    putchar('\n');
    printf("Using %zu X %zu pattern:\n", pat_rows, pat_cols);
    putchar('\n');
    print_array(pat_rows, pat_cols, pattern);

    putchar('\n');
    printf("Similar pattern %s in array\n",
           contains_similar(arr_rows, arr_cols, array,
                            pat_rows, pat_cols, pattern)
           ? "found"
           : "not found");

    return 0;
}

int contains_similar(size_t rows,
                     size_t cols,
                     char arr[rows][cols],
                     size_t prows,
                     size_t pcols,
                     char pat[prows][pcols])
{
    char temp[prows][pcols];
    size_t last_row = rows - prows;
    size_t last_col = cols - pcols;
    size_t pat_sz = prows * pcols;

    /* i and j index the upper-left corner of the region of interest */
    for (size_t i = 0; i <= last_row; i++) {
        for (size_t j = 0; j <= last_col; j++) {

            /* Copy region of interest to temp[][] */
            for (size_t k = 0; k < prows; k++) {
                memcpy(temp[k], &arr[i+k][j], pcols);
            }

            /* Make comparisons with transformations */
            if (memcmp(temp, pat, pat_sz) == 0) {      // pattern matched
                return 1;
            }

            reverse_rows (prows, pcols, temp);
            if (memcmp(temp, pat, pat_sz) == 0) {      // pattern matched
                return 1;
            }
        }
    }

    return 0;                                          // no match found
}

void reverse_rows(size_t rows, size_t cols, char arr[rows][cols])
{
    char temp[cols];
    size_t swap_row = rows - 1;

    for (size_t i = 0; i < swap_row; i++) {
        memcpy(temp, arr[i], cols);
        memmove(arr[i], arr[swap_row], cols);
        memcpy(arr[swap_row], temp, cols);
        --swap_row;
    }
}

void print_array(size_t rows, size_t cols, char arr[rows][cols])
{
    for (size_t i = 0; i < rows; i++) {
        for (size_t j = 0; j < cols; j++) {
            putchar(arr[i][j]);
        }
        putchar('\n');
    }
}

Program output:

Working with 10 X 10 array:

oooooooooo
oooooooooo
ooxoooxooo
ooxxxxxoox
oxxoooooox
oxooooooox
oxxoxxooox
ooxoxoooxx
oxxoxooooo
ooooxxxxxo

Using 2 X 5 pattern:

xxxxx
xooox

Similar pattern found in array

Checking for pattern rotations

The above code works fine for some uses, but will not work easily with OP goal of checking for rotated patterns within the larger pattern. Non-square patterns will change shape under rotation, and will fit into the larger pattern differently before and after rotation.

The above code could be reconfigured to check the larger pattern against a sub-pattern, then against a rotated sub-pattern, etc. While reconfiguring, the pattern arrays could be wrapped in structures. These structures can contain arrays which are larger than the anticipated patterns, and can also contain the sizes of the actual patterns. It is convenient to keep pattern dimensions together with the representation of the pattern. The larger pattern, sub-pattern, and region of interest are all stored in such Pattern struct s.

The memcmp() function can still be used to compare patterns, but now entire oversized arrays are compared. This may not be the most efficient comparison method. Note that memcpy() is no longer used to copy the region of interest, though it could be; here a nested loop was used instead for variety.

This version also stores the locations of pattern matches. The Matches struct contains an array of Coordinate struct s large enough ( ARR_SZ * ARR_SZ members) to hold matches if every location in the pattern is a match. When a match is found, the indices of the top-left corner of the matching sub-pattern are stored in the array, and the number matches .num is incremented.

The large pattern is a modified version of the posted example input, which contains a few pattern matches in different orientations. In main() the large and small patterns are initialized, and the found structure is initialized to 0 . The find_similar() function is called; this function calls find_pattern() with the small pattern and rotations of this pattern. When find_similar() returns, a message is printed to indicate whether any matches were found, and if so the locations of the matching patterns is displayed.

If OP is unhappy with the use of struct s in this solution, certainly a satisfactory solution between the two presented here can be found.

#include <stdio.h>
#include <string.h>

#define ARR_SZ  100

struct Pattern
{
    size_t nrows;
    size_t ncols;
    char arr[ARR_SZ][ARR_SZ];
};

struct Coordinate
{
    size_t row;
    size_t col;
};

struct Matches
{
    size_t num;
    struct Coordinate location[ARR_SZ * ARR_SZ];
};

int find_pattern(struct Pattern pat,
                 struct Pattern sub,
                 struct Matches *found);

int find_similar(struct Pattern pat,
                 struct Pattern sub,
                 struct Matches *found);

void print_pattern(struct Pattern pat);
struct Pattern rotate_pattern(struct Pattern pat);

int main(void)
{
    struct Pattern large = {
        .arr = {
            { 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o' },
            { 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o' },
            { 'o', 'o', 'x', 'o', 'o', 'o', 'x', 'o', 'o', 'o' },
            { 'o', 'x', 'x', 'x', 'x', 'x', 'x', 'o', 'x', 'x' },
            { 'o', 'x', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'x' },
            { 'o', 'x', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'x' },
            { 'o', 'x', 'o', 'o', 'x', 'x', 'o', 'o', 'o', 'x' },
            { 'o', 'x', 'x', 'o', 'x', 'o', 'o', 'o', 'x', 'x' },
            { 'o', 'x', 'x', 'o', 'x', 'o', 'o', 'o', 'x', 'o' },
            { 'o', 'o', 'o', 'o', 'x', 'x', 'x', 'x', 'x', 'o' }
        }
    };
    large.ncols = 10;
    large.nrows = 10;

    struct Pattern small = {
        .arr = {
            { 'x', 'x', 'x', 'x', 'x' },
            { 'x', 'o', 'o', 'o', 'x' }
        }
    };
    small.ncols = 5;
    small.nrows = 2;

    struct Matches found = { .num = 0 };

    printf("Working with %zu X %zu array:\n", large.nrows, large.ncols);
    putchar('\n');
    print_pattern(large);

    putchar('\n');
    printf("Using %zu X %zu pattern:\n", small.nrows, small.ncols);
    putchar('\n');
    print_pattern(small);

    int ret = find_similar(large, small, &found);
    putchar('\n');
    printf("Similar patterns %s in array\n", ret ? "found" : "not found");

    if (ret) {
        for (size_t i = 0; i < found.num; i++) {
            printf("[%zu, %zu]\n",
                   found.location[i].row,
                   found.location[i].col);
        }
    }

    return 0;
}

int find_pattern(struct Pattern pat,
                 struct Pattern sub,
                 struct Matches *found)
{
    static size_t max_found = sizeof found->location / sizeof *found->location;
    int ret = 0;

    size_t rows = pat.nrows;
    size_t cols = pat.ncols;
    size_t srows = sub.nrows;
    size_t scols = sub.ncols;
    size_t last_row = rows - srows;
    size_t last_col = cols - scols;

    struct Pattern roi = { .nrows = srows,
                           .ncols = scols,
                           .arr = { { 0 } } };

    /* i and j index the upper-left corner of the region of interest */
    for (size_t i = 0; i <= last_row; i++) {
        for (size_t j = 0; j <= last_col; j++) {

            /* Copy region of interest to roi */
            for (size_t k = 0; k < srows; k++) {
                for (size_t l = 0; l < scols; l++) {
                    roi.arr[k][l] = pat.arr[i + k][j + l];
                }
            }

            /* Make comparison */
            if (memcmp(roi.arr, sub.arr, sizeof roi.arr) == 0) {

                /* Store location of match */
                struct Coordinate *cdt = &found->location[found->num];
                cdt->row = i;
                cdt->col = j;
                found->num += 1;
                if (found->num > max_found) {
                    found->num = max_found;
                }
                ret = 1;
            }
        }
    }

    return ret;
}

int find_similar(struct Pattern pat,
                 struct Pattern sub,
                 struct Matches *found)
{
    int ret = find_pattern(pat, sub, found);
    struct Pattern rot = sub;
    for (int i = 0; i < 3; i++) {
        rot = rotate_pattern(rot);
        ret = find_pattern(pat, rot, found) || ret;
    }

    return ret;
}

void print_pattern(struct Pattern pat)
{
    size_t rows = pat.nrows;
    size_t cols = pat.ncols;

    for (size_t i = 0; i < rows; i++) {
        for (size_t j = 0; j < cols; j++) {
            putchar(pat.arr[i][j]);
        }
        putchar('\n');
    }
}

struct Pattern rotate_pattern(struct Pattern pat)
{
    size_t rows = pat.nrows;
    size_t cols = pat.ncols;

    struct Pattern rotated = { .nrows = cols, .ncols = rows };
    for (size_t i = 0; i < rows; i++) {
        for (size_t j = 0; j < cols; j++) {
            rotated.arr[j][rows - i - 1] = pat.arr[i][j];
        }
    }

    return rotated;
}

Program output:

Working with 10 X 10 array:

oooooooooo
oooooooooo
ooxoooxooo
oxxxxxxoxx
oxooooooox
oxooooooox
oxooxxooox
oxxoxoooxx
oxxoxoooxo
ooooxxxxxo

Using 2 X 5 pattern:

xxxxx
xooox

Similar patterns found in array
[3, 8]
[2, 2]
[8, 4]
[3, 1]

What I can think of right now is using the Two Pointers technique by traversing the smaller and larger array simultaneously and checking for similarities.

You'll still need to enhance it a little bit to be able to check for rows which are identically over each other.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM