Yuriy
Yuriy

Reputation: 71

what is the better way to loop this problem?

#include <stdio.h>

int main()
{
int arr[9][9];
int i = 0, x = 10;

for (int i = 0, j = 0; j <= 8; j++) {
    x++;
    arr[i][j] = x;
}
for (int j = 8, i = 1; i <= 8; i++) {
    x++;
    arr[i][j] = x;
}
for (int i = 8, j = 7; j >= 0; j--) {
    x++;
    arr[i][j] = x;
}
for (int j = 0, i = 7; i >= 1; i--) {
    x++;
    arr[i][j] = x;
}

for (int i = 1, j = 1; j <= 7; j++) {
    x++;
    arr[i][j] = x;
}
for (int j = 7, i = 2; i <= 7; i++) {
    x++;
    arr[i][j] = x;
}
for (int i = 7, j = 6; j >= 1; j--) {
    x++;
    arr[i][j] = x;
}
for (int j = 1, i = 6; i >= 2; i--) {
    x++;
    arr[i][j] = x;
}
...
arr[4][4] = x + 1;


for (int i = 0; i <= 8; i++) {
    for (int j = 0; j <= 8; j++)
        printf("%d ", arr[i][j]);
    printf("\n");
}
getch();
}

so I have this program, and I know you can loop it but how ? been sitting for an hour thinking and nothing came to my mind. By the way, the task is to append a matrix like on picture. Does anyone know to do it ? Maybe use some complex for loopenter image description here

Upvotes: 1

Views: 212

Answers (4)

Neil
Neil

Reputation: 1922

It's possible to deterministically compute any one entry in the array A_{i,j} as a function only given the array size N, and i, j, in O(1), on-line, without any state, noticing the radius is a geometric progression. The space requirement is O(1) since one doesn't actually need the array to store the values; we can scan the array sequentially. However, like ray-tracing, it probably is slower, (up to a constant, it's still O(N^2).)

#include <stdio.h>

/* N: The size of the (simulated) array. */
#define N (16)

/* i, j: The array indices, as if, a[i][j]. */
static int a(const int i, const int j) {
    /* (x,y) translation of (i,-j) to the centre, scaled up 2x for int math. */
    const int x = 2 * i + 1 - N, y = -2 * j - 1 + N;
    /* Geometric series and an offset +fiddling to get the directionality. */
    return N*N - ((x < -y) ?
        (-x > -y) ? (x+1)*(x+1) - (y+x)/2 - 1: y*y + (x+y)/2 :
        (x > y) ? x*x + (x+y)/2 : (y+1)*y + (-x+y)/2);
}

int main(void) {
    int i, j;
    for(j = 0; j < N; j++) {
        for(i = 0; i < N; i++) {
            printf("%3d ", a(i, j));
        }
        printf("\n");
    }
    return 0;
}

Upvotes: 0

KamilCuk
KamilCuk

Reputation: 140960

My solution. Using an "object" struct strangeite_s (from strange ite-rator). It allows ease reusing on different arrays and probably could be even rescaled to support n-dimensional arrays.
The strangeite is initialized using _init function with specified dimensions sizes of an 2d array. Each time _loop is evaluated, the x and y positions are updated and the condition for loop end is checked (and returned). The _inc function should be called on each increment of the iterator.

#include <stdio.h>
#include <limits.h>
#include <stddef.h>
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>

struct strangeite_s {
    size_t steplen[2];
    size_t idx[2];
    size_t cursteplen;
    int direction;
};

void strangeite_init(struct strangeite_s *t, size_t max_x, size_t max_y)
{
    assert(t != NULL);
    t->steplen[0] = max_y;
    t->steplen[1] = max_x;
    memset(t->idx, 0, sizeof(t->idx));
    t->direction = 0;
    t->cursteplen = t->steplen[0];
}

bool strangeite_loop(const struct strangeite_s *t, size_t *x, size_t *y)
{
    if (x) *x = t->idx[0];
    if (y) *y = t->idx[1];
    for (size_t i = 0; i < sizeof(t->steplen)/sizeof(t->steplen[0]); ++i) {
        if (t->steplen[i] == 0) {
            return false;
        }
    }
    return true;
}

void strangeite_inc(struct strangeite_s *t)
{
    if (t->cursteplen != 1) {
        --t->cursteplen;
    } else {
        t->direction = ++t->direction % (2 * 2);
        t->cursteplen = --t->steplen[t->direction % 2];
    }
    const size_t idx_to_change = t->direction % 2;
    t->idx[idx_to_change] = t->idx[idx_to_change] + ( t->direction < 2 ? +1 : -1 );
}

int main()
{
    int var[5][5];

    struct strangeite_s  i;
    strangeite_init(&i, 5, 5);
    int idx = 0;
    for (size_t x, y; strangeite_loop(&i, &x, &y); strangeite_inc(&i)) {
        var[y][x] = ++idx; 
    }

    for (size_t i = 0; i < 5; ++i) {
        for (size_t j = 0; j < 5; ++j) {
            printf("%d ", var[i][j]);
        }
        printf("\n");
    }

    return 0;
}

Produces the following output:

1 2 3 4 5                                                                                                                                                                                                                                                   
16 17 18 19 6                                                                                                                                                                                                                                               
15 24 25 20 7                                                                                                                                                                                                                                               
14 23 22 21 8                                                                                                                                                                                                                                               
13 12 11 10 9     

Live version at onlinegdb.

Upvotes: 0

Alex Lop.
Alex Lop.

Reputation: 6875

Here is the "straight forward" option with for loops:

#include <stdio.h>

#define N 5

int main(void) {
    int i,j,dim;
    int matrix[N][N];

    // init and print the matrix
    for (i=0; i < N; i++)
    {
        for (j=0; j< N; j++)
        {
            matrix[i][j] = i*N + j;
            printf("%2d ", matrix[i][j]);
        }
        printf("\n");
    }

    printf("\n");

    // perform spiral print
    for (dim = 0; dim < (N+1)/2; dim++)
    {
        // set initial i and go till the "last column"
        i = dim;
        for (j = dim; j < N - dim; j++)
        {
            printf("%2d ", matrix[i][j]);
        }
        printf("\n");

        // bring back i and j to the proper coordinate
        // and move down to the "last row"
        j--;i++;
        for (; i < N - dim; i++)
        {
            printf("%2d ", matrix[i][j]);
        }
        printf("\n");

        // bring back i and j to the proper coordinate
        // and move back to the "first column"
        i--;j--;
        for (; j >= dim; j--)
        {
            printf("%2d ", matrix[i][j]);
        }
        printf("\n");

        // bring back i and j to the proper coordinate
        // and move up to the "first row"
        j++;i--;
        for (; i > dim; i--)
        {
            printf("%2d ", matrix[i][j]);
        }
        printf("\n");
    }

    return 0;
}

The output, as can be seen here is

 0  1  2  3  4 
 5  6  7  8  9 
10 11 12 13 14 
15 16 17 18 19 
20 21 22 23 24 

 0  1  2  3  4 
 9 14 19 24 
23 22 21 20 
15 10  5 
 6  7  8 
13 18 
17 16 
11 
12 

==========================================================================

Looks like I misunderstood the question but the step from "printing" clockwise to "setting" clockwise is really small. Here is the setting flow:

#include <stdio.h>

#define N 5

int main(void) {
    int i,j,dim, val = 1;
    int matrix[N][N];

    // perform spiral print
    for (dim = 0; dim < (N+1)/2; dim++)
    {
        // set initial i and go till the "last column"
        i = dim;
        for (j = dim; j < N - dim; j++)
        {
            matrix[i][j] = val++;
        }

        // bring back i and j to the proper coordinate
        // and move down to the "last row"
        j--;i++;
        for (; i < N - dim; i++)
        {
            matrix[i][j] = val++;
        }

        // bring back i and j to the proper coordinate
        // and move back to the "first column"
        i--;j--;
        for (; j >= dim; j--)
        {
            matrix[i][j] = val++;
        }

        // bring back i and j to the proper coordinate
        // and move up to the "first row"
        j++;i--;
        for (; i > dim; i--)
        {
            matrix[i][j] = val++;
        }
    }

    // print the matrix
    for (i=0; i < N; i++)
    {
        for (j=0; j< N; j++)
        {
            printf("%2d ", matrix[i][j]);
        }
        printf("\n");
    }

    return 0;
}

The output as shown here is

 1  2  3  4  5 
16 17 18 19  6 
15 24 25 20  7 
14 23 22 21  8 
13 12 11 10  9 

Upvotes: 1

Nelfeal
Nelfeal

Reputation: 13269

Here's one way to do it:

int arr[9][9] = {0};
int x = 0, i = 0, j = 0, vi = 0, vj = 1;

do {
    ++x;
    arr[i][j] = x;

    {
        int ii = i+vi;
        int jj = j+vj;
        if (ii < 0 || ii >= 9 || jj < 0 || jj >= 9 || arr[ii][jj] != 0) {
            if (vi != 0) {
                vj = -vi;
                vi = 0;
            } else {
                vi = vj;
                vj = 0;
            }
        }
    }

    i = i+vi;
    j = j+vj;
} while (arr[i][j] == 0);

Live on Coliru

Here's another way:

int arr[9][9] = {0};
int x = 0, i = 0, j = 0, vi = 0, vj = 1, lk = 8;

while (lk > 0) {
    for (int k = 0; k < lk; ++k) {
        ++x;
        arr[i][j] = x;
        i += vi;
        j += vj;
    }

    vi = vj;
    vj = 0;

    for (int k = 0; k < lk; ++k) {
        ++x;
        arr[i][j] = x;
        i += vi;
        j += vj;
    }

    vj = -vi;
    vi = 0;

    if (vj > 0) {
        ++i;
        ++j;
        lk -= 2;
    }
}

arr[9/2][9/2] = x+1; // Only if odd dimensions

Live on Coliru

And here is yet another:

int arr[9][9] = {0};
int i = 0, lk = 8, x = 1;

while (lk > 0) {
    for (int k = 0; k < lk; ++k) {
        arr[i][i+k] = x + k;
        arr[i+k][lk+i] = x + lk + k;
        arr[lk+i][lk+i-k] = x + 2*lk + k;
        arr[lk+i-k][i] = x + 3*lk + k;
    }

    x += 4*lk;
    lk -= 2;
    ++i;
}

arr[9/2][9/2] = x; // Only if odd dimensions

Live on Coliru

Upvotes: 1

Related Questions