Loop through 2-dim matrix diagonally, but the other way - c

I'm having trouble looping through an NxM matrix the other way.
This probably isn't everything I could have tried but I already tried finding this on google, and using all kind of different border-values, also tried substracting one index of the other over and over, but I can't seem to get a hang of it. The last thing I did, was create a copy of the matrix, and swap the rows through by for loop until last was first and first was last. this works, but is not what I want.
The Loop down there starts at the top Left of the matrix and works through from bottom left to top right. I want anotherone to start at the bottom left and work through from bottom right to top left, or from top left to bottom right.
Loop:
for(int i = 0; i + 1 < ROWCOUNT + COLCOUNT; i++) {
printf("\n");
for(int j = 0; j - 1 < i; j++) {
int n = i - j;
int m = j;
if(n < ROWCOUNT && m < COLCOUNT) {
printf(" %d %d ", n, m);
}
}
}
Output:
0 0
1 0 0 1
2 0 1 1 0 2
3 0 2 1 1 2 0 3
4 0 3 1 2 2 1 3 0 4
5 0 4 1 3 2 2 3 1 4 0 5
5 1 4 2 3 3 2 4 1 5
5 2 4 3 3 4 2 5
5 3 4 4 3 5
5 4 4 5
5 5
EDIT: I will try to show you what I'm trying to do.
A B C D E F
G H I J K L
M N O P Q R
S T U V W X
Y Z AA AB AC AD
AE AF AG AH AI AJ
My loop goes through this 6x6 matrix the following way:
A
G B
M H C
S N I D
Y T O J E
AE Z U P K F
AF AA V Q L
AG AB W R
AH AC X
AI AD
AJ
I am searching for a loop to go trough the other way. Basically somehow like this:
AE
AF Y
AG Z S
AH AA T M
AI AB U N G
AJ AC V O H A
AD W P I B
R K D
L E
F
EDIT: #pmg provided me with a solution. Thanks!

Not sure about what you are looking for, but just loop on the other way:
#include "stdio.h"
#define ROWCOUNT 6
#define COLCOUNT 6
int main(void) {
for(int i = ROWCOUNT - 1; i >= 0; i--) {
for(int j = 0; j < COLCOUNT; j++) {
printf(" %d %d ", i, j);
}
printf("\n");
}
}
output
5 0 5 1 5 2 5 3 5 4 5 5
4 0 4 1 4 2 4 3 4 4 4 5
3 0 3 1 3 2 3 3 3 4 3 5
2 0 2 1 2 2 2 3 2 4 2 5
1 0 1 1 1 2 1 3 1 4 1 5
0 0 0 1 0 2 0 3 0 4 0 5

Both diagonals have the property that every cell indices add to a constant or their difference is constant. In your case, the indices must add to a constant. Just consider a cell (the first cell to be printed) that is on the diagonal you want, and then as you add to one index, subtract to the other the same quantity, making the sum the same. This way you can begin with an add of zero:
i = 0; j = 0;
then, add one to the sum and follow:
pru.c:
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
int N = 10;
int main(int argc, char **argv)
{
int opt;
while ((opt = getopt(argc, argv, "n:")) != EOF) {
switch(opt) {
case 'n': N = atoi(optarg); break;
}
} /* while */
int sum;
/* maximum value is (N-1) + (N-1) = 2N-2 */
for (sum = 0; sum <= 2*N - 2; sum++) {
/* initial values */
int i = sum < N ? sum : N-1; /* will be decremented */
int j = sum - i; /* must add to sum, will be incremented */
char *sep = "";
for (; i >= 0 && j < N; i--, j++) {
printf("%sA[%d, %d]", sep, i, j);
sep = " -> ";
}
printf("\n");
}
}
The example code prints the sequence of indices to print:
$ pru -n 5
A[0, 0]
A[1, 0] -> A[0, 1]
A[2, 0] -> A[1, 1] -> A[0, 2]
A[3, 0] -> A[2, 1] -> A[1, 2] -> A[0, 3]
A[4, 0] -> A[3, 1] -> A[2, 2] -> A[1, 3] -> A[0, 4]
A[4, 1] -> A[3, 2] -> A[2, 3] -> A[1, 4]
A[4, 2] -> A[3, 3] -> A[2, 4]
A[4, 3] -> A[3, 4]
A[4, 4]
In the case of the difference of indices, you have:
pru2.c
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
int N = 10;
int main(int argc, char **argv)
{
int opt;
while ((opt = getopt(argc, argv, "n:")) != EOF) {
switch(opt) {
case 'n': N = atoi(optarg); break;
}
} /* while */
int dif;
/* difference ranges from -(N-1) to +(N-1) */
for (dif = -N+1; dif <= N-1; dif++) {
/* initial values, dif = i - j */
int i = dif > 0 ? 0 : dif; /* will be incremented */
int j = dif > 0 ? -dif : 0; /* will be incremented */
char *sep = "";
for (; i < N && j < N; i++, j++) {
printf("%sA[%d, %d]", sep, i, j);
sep = " -> ";
}
printf("\n");
}
}
that will give:
A[4, 0]
A[3, 0] -> A[4, 1]
A[2, 0] -> A[3, 1] -> A[4, 2]
A[1, 0] -> A[2, 1] -> A[3, 2] -> A[4, 3]
A[0, 0] -> A[1, 1] -> A[2, 2] -> A[3, 3] -> A[4, 4]
A[0, 1] -> A[1, 2] -> A[2, 3] -> A[3, 4]
A[0, 2] -> A[1, 3] -> A[2, 4]
A[0, 3] -> A[1, 4]
A[0, 4]

Related

Represent a tridiagonal sparse matrix in column major order

Main Question:-
If the elements in the band formed by the three diagonals of a tridiagonal matrix X are represented column-wise in an array Y, with X[1,1] being stored in Y[1], then write an algorithm to determine the value of X[i, j], 1 <= i, j <= n from array Y.
I did some calculation in rough and found the size of 1D array required and index to row and column index for main diagonal and upper diagonal but failing to do so for lower diagonal
CONSIDERING A MATRIX WITH 5 ROWS AND 5 COLUMNS
|A11 A12 0 0 0 |
|A21 A22 A23 0 0 |
| 0 A32 A33 A34 0 |
| 0 0 A43 A44 A45|
| 0 0 0 A54 A55|
Size of the array (3*n - 2),
here size of the array = (3*5 - 2) = 13
0 1 2 3 4 5 6 7 8 9 10 11 12
A11 A21 A12 A22 A32 A23 A33 A43 A34 A44 A54 A45 A55
i=row index, 1<=i<=N
j=column index, 1<=j<=N
k=array index
Now for main diagonal
i j k
1 1 0
2 2 3
3 3 6
4 4 9
5 5 12
I got the relation as 3i - 3
For Upper diagonal
i j k
1 2 2
2 3 5
3 4 8
4 5 11
I got the relation as 4i - j
Now for lower diagonal(question)
i j k
2 1 1
3 2 4
4 3 7
5 4 10
Relation ??
Summary
You'll find that (indexing from 1), for an NxN tridiagonal matrix X
linearized in column-major order into an array Z, the entry in row r:
On the main diagonal of X is at index (3 * c - 2) of Y for c = 1..N;
On the upper-diagonal of X is at (3 * c - 3) of Y (for c = 1..N-1);
On the lower-diagonal of X is at (3 * c - 1) of Y (for c = 2..N).
For an element with row r, column c (both in the range 1..N):
if |r - c| > 1 then the value is zero;
if c == r then it is on the leading diagonal;
if c = r + 1 then it is on the upper diagonal;
if c = r - 1 then it is on the lower diagonal.
Of course, in C, arrays are indexed from zero, not one.
Cogitations
NxN tri-diagonal matrix X
Linearized in row-major order into array Y with 3*N-2 entries
Linearized in column-major order into array Z with 3*N-2 entries
Non-zero elements have c = r + { -1, 0, +1 }
Equivalently they have r = c + { -1, 0, +1 }
With one-based indexing, the first row with an element on the lower
diagonal is r = 2 and the last row with an element on the upper
diagonal is r = N - 1.
With zero-based indexing, the first row with an element on the lower
diagonal is r = 1 and the last rows with an element on the upper
diagonal is r = N - 2.
In the linearized vectors, the notation is:
D = diagonal, L = lower diagonal, U = upper diagonal
Row-Major Order with Zero-Based Indexing
X c = 0 1 2 3 4 5
+----------------------
r = 0 | 1 2 0 0 0 0
r = 1 | 3 4 5 0 0 0
r = 2 | 0 6 7 8 0 0
r = 3 | 0 0 9 10 11 0
r = 4 | 0 0 0 12 13 14
r = 5 | 0 0 0 0 15 16
D U L D U L D U L D U L D U L D
Y = { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 }
Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Elements on main diagonal at indexes: 0, 3, 6, 9, 12, 15
Elements on upper diagonal at indexes: 1, 4, 7, 10, 13
Elements on lower diagonal at indexes: 2, 5, 8, 11, 14
Function get_rm_0():
X[r,c] = 0 if |r - c| > 1
X[r,c] = 3 * r + 0 if r == c + 0 — Main diagonal
X[r,c] = 3 * r + 1 if r == c - 1 — Upper diagonal
X[r,c] = 3 * r - 1 if r == c + 1 — Lower diagonal
Always subject to 0 <= r < N; 0 <= c < N
Row-Major Order with One-Based Indexing
X c = 1 2 3 4 5 6
+----------------------
r = 1 | 1 2 0 0 0 0
r = 2 | 3 4 5 0 0 0
r = 3 | 0 6 7 8 0 0
r = 4 | 0 0 9 10 11 0
r = 5 | 0 0 0 12 13 14
r = 6 | 0 0 0 0 15 16
D U L D U L D U L D U L D U L D
Y = { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 }
Index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Elements on main diagonal at indexes: 1, 4, 7, 10, 13, 16
Elements on upper diagonal at indexes: 2, 5, 8, 11, 14
Elements on lower diagonal at indexes: 3, 6, 9, 12, 15
Function get_rm_1():
X[r,c] = 0 if |r - c| > 1
X[r,c] = 3 * r - 2 if r == c + 0 — Main diagonal
X[r,c] = 3 * r - 1 if r == c - 1 — Upper diagonal
X[r,c] = 3 * r - 3 if r == c + 1 — Lower diagonal
Always subject to 0 < r <= N; 0 <= c <= N
Column-major instead of row-major order
You are correct. Here you are considering row-major order. I
wanted to store the elements in the array as:
Z = { 1, 3, 2, 4, 6, 5, 7, 9, 8, 10, 12, 11, 13, 15, 14, 16 }
as per your example
Column-Major Order with One-Based Indexing
So, you can make a parallel argument to the one I gave. Annotate
your column-major array Z similarly to the way I annotated the
row-major array Y:
D L U D L U D L U D L U D L U D
Z = { 1, 3, 2, 4, 6, 5, 7, 9, 8, 10, 12, 11, 13, 15, 14, 16 }
Index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Elements on main diagonal at indexes: 1, 4, 7, 10, 13, 16
Elements on upper diagonal at indexes: 3, 6, 9, 12, 15
Elements on lower diagonal at indexes: 2, 5, 8, 11, 14
Function get_cm_1():
X[r,c] = 0 if |c - r| > 1
X[r,c] = 3 * c - 2 if c == r + 0 — Main diagonal
X[r,c] = 3 * c - 3 if c == r + 1 — Upper diagonal
X[r,c] = 3 * c - 1 if c == r - 1 — Lower diagonal
Always subject to 0 < r <= N; 0 < c <= N.
Column-Major Order with Zero-Based Indexing
D L U D L U D L U D L U D L U D
Z = { 1, 3, 2, 4, 6, 5, 7, 9, 8, 10, 12, 11, 13, 15, 14, 16 }
Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Elements on main diagonal at indexes: 0, 3, 6, 9, 12, 15
Elements on upper diagonal at indexes: 2, 5, 8, 11, 14
Elements on lower diagonal at indexes: 1, 4, 7, 10, 13
Function get_cm_0():
X[r,c] = 0 if |c - r| > 1
X[r,c] = 3 * c + 0 if c == r + 0 — Main diagonal
X[r,c] = 3 * c - 1 if c == r + 1 — Upper diagonal
X[r,c] = 3 * c + 1 if c == r - 1 — Lower diagonal
Always subject to 0 <= r < N; 0 <= c < N.
Code
Source file td59.c:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
enum { N = 6 };
static const int X[N][N] =
{
{ 1, 2, 0, 0, 0, 0 },
{ 3, 4, 5, 0, 0, 0 },
{ 0, 6, 7, 8, 0, 0 },
{ 0, 0, 9, 10, 11, 0 },
{ 0, 0, 0, 12, 13, 14 },
{ 0, 0, 0, 0, 15, 16 },
};
static const int Y[3*N-2] =
{
1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16,
};
static const int Z[3*N-2] =
{
1, 3, 2, 4, 6, 5, 7, 9,
8, 10, 12, 11, 13, 15, 14, 16,
};
/* rm = row major, cm = column major, 0 = zero-based, 1 = one-based */
static int get_rm_0(int r, int c)
{
assert(r >= 0 && r < N);
assert(c >= 0 && c < N);
//printf("%s(): r = %d, c = %d\n", __func__, r, c);
if (abs(r - c) > 1) /* Off tridiagonal */
return 0;
int index;
if (r == c) /* Main diagonal */
index = 3 * r + 0;
else if (r == c - 1) /* Upper diagonal */
index = 3 * r + 1;
else
{
assert(r == c + 1);
index = 3 * r - 1; /* Lower diagonal */
}
//printf("%s(): r = %d, c = %d, i = %d, v = %d\n", __func__, r, c, index, Y[index]);
return Y[index];
}
static int get_rm_1(int r, int c)
{
assert(r > 0 && r <= N);
assert(c > 0 && c <= N);
//printf("%s(): r = %d, c = %d\n", __func__, r, c);
if (abs(r - c) > 1) /* Off tridiagonal */
return 0;
int index;
if (r == c) /* Main diagonal */
index = 3 * r - 2;
else if (r == c - 1) /* Upper diagonal */
index = 3 * r - 1;
else
{
assert(r == c + 1);
index = 3 * r - 3; /* Lower diagonal */
}
//printf("%s(): r = %d, c = %d, i = %d, v = %d\n", __func__, r, c, index, Y[index-1]);
return Y[index-1];
}
static int get_cm_0(int r, int c)
{
assert(r >= 0 && r < N);
assert(c >= 0 && c < N);
//printf("%s(): r = %d, c = %d\n", __func__, r, c);
if (abs(r - c) > 1) /* Off tridiagonal */
return 0;
int index;
if (c == r) /* Main diagonal */
index = 3 * c + 0;
else if (c == r + 1) /* Upper diagonal */
index = 3 * c - 1;
else
{
assert(c == r - 1);
index = 3 * c + 1; /* Lower diagonal */
}
//printf("%s(): r = %d, c = %d, i = %d, v = %d\n", __func__, r, c, index, Z[index]);
return Z[index];
}
static int get_cm_1(int r, int c)
{
assert(r > 0 && r <= N);
assert(c > 0 && c <= N);
//printf("%s(): r = %d, c = %d\n", __func__, r, c);
if (abs(r - c) > 1) /* Off tridiagonal */
return 0;
int index;
if (c == r) /* Main diagonal */
index = 3 * c - 2;
else if (c == r + 1) /* Upper diagonal */
index = 3 * c - 3;
else
{
assert(c == r - 1);
index = 3 * c - 1; /* Lower diagonal */
}
//printf("%s(): r = %d, c = %d, i = %d, v = %d\n", __func__, r, c, index, Z[index-1]);
return Z[index-1];
}
static void dump_matrix(const char *tag, int rows, int cols,
const int matrix[rows][cols], int base)
{
printf("%s (%dx%d) %d-based:\n", tag, rows, cols, base);
printf(" c =");
for (int c = 0; c < cols; c++)
printf(" %2d", c + base);
putchar('\n');
for (int r = 0; r < rows; r++)
{
printf("r = %d: {", r + base);
for (int c = 0; c < cols; c++)
printf(" %2d", matrix[r][c]);
puts(" }");
}
putchar('\n');
}
static void dump_vector(const char *tag, int values, const int vector[values], int base)
{
printf("Vector %s (%d) %d-based:\n", tag, values, base);
int len = 0;
const char *pad = "";
for (int i = 0; i < values; i++)
{
len += printf("%s[%2d] = %2d,", pad, i + base, vector[i]);
pad = " ";
if (len > 80)
{
putchar('\n');
len = 0;
pad = "";
}
}
if (len > 0)
putchar('\n');
putchar('\n');
}
static void reconstruct_matrix(const char *matrix_tag, const char *vector_tag,
int values, const int vector[values],
int rows, int cols, int (*getter)(int r, int c), int base)
{
dump_vector(vector_tag, values, vector, base);
printf("%s (%dx%d) %d-based:\n", matrix_tag, rows, cols, base);
for (int r = 0 + base; r < rows + base; r++)
{
printf("r = %d: {", r);
for (int c = 0 + base; c < cols + base; c++)
printf(" %2d", (*getter)(r, c));
puts(" }");
}
putchar('\n');
}
int main(void)
{
dump_matrix("Tridiagonal matrix X", N, N, X, 0);
reconstruct_matrix("Reconstructed Row-Major Matrix", "Y", 3 * N - 2, Y, N, N, get_rm_0, 0);
dump_matrix("Tridiagonal matrix X", N, N, X, 1);
reconstruct_matrix("Reconstructed Row-Major Matrix", "Y", 3 * N - 2, Y, N, N, get_rm_1, 1);
puts("\n\n");
dump_matrix("Tridiagonal matrix X", N, N, X, 0);
reconstruct_matrix("Reconstructed Column-Major Matrix", "Z", 3 * N - 2, Z, N, N, get_cm_0, 0);
dump_matrix("Tridiagonal matrix X", N, N, X, 1);
reconstruct_matrix("Reconstructed Column-Major Matrix", "Z", 3 * N - 2, Z, N, N, get_cm_1, 1);
return 0;
}
There are many possible changes that could be made to this code.
Use functions get_[cr]m_[01]_idx() to get the array index in the vector. They would return -1 when the cell is off the tri-diagonal.
Use a modified vector (Y, Z) which has an extra element with value 0 at the start. Use const int *Y1 = &Y[1]; and then you can use: int val = Y1[get_rm_1_idx(r, c)]; to get the value.
Revise the get_[cr]m_[01]() functions to take the vector instead of using global variables Y and Z.
Rename the functions get_[cr]m_[01]() functions using get_[cr]m_[01]_val() to indicate that they get the value.
Add printing to report the index into the vectors Y and Z at which the value is found.
Output
Tridiagonal matrix X (6x6) 0-based:
c = 0 1 2 3 4 5
r = 0: { 1 2 0 0 0 0 }
r = 1: { 3 4 5 0 0 0 }
r = 2: { 0 6 7 8 0 0 }
r = 3: { 0 0 9 10 11 0 }
r = 4: { 0 0 0 12 13 14 }
r = 5: { 0 0 0 0 15 16 }
Vector Y (16) 0-based:
[ 0] = 1, [ 1] = 2, [ 2] = 3, [ 3] = 4, [ 4] = 5, [ 5] = 6, [ 6] = 7, [ 7] = 8,
[ 8] = 9, [ 9] = 10, [10] = 11, [11] = 12, [12] = 13, [13] = 14, [14] = 15, [15] = 16,
Reconstructed Row-Major Matrix (6x6) 0-based:
r = 0: { 1 2 0 0 0 0 }
r = 1: { 3 4 5 0 0 0 }
r = 2: { 0 6 7 8 0 0 }
r = 3: { 0 0 9 10 11 0 }
r = 4: { 0 0 0 12 13 14 }
r = 5: { 0 0 0 0 15 16 }
Tridiagonal matrix X (6x6) 1-based:
c = 1 2 3 4 5 6
r = 1: { 1 2 0 0 0 0 }
r = 2: { 3 4 5 0 0 0 }
r = 3: { 0 6 7 8 0 0 }
r = 4: { 0 0 9 10 11 0 }
r = 5: { 0 0 0 12 13 14 }
r = 6: { 0 0 0 0 15 16 }
Vector Y (16) 1-based:
[ 1] = 1, [ 2] = 2, [ 3] = 3, [ 4] = 4, [ 5] = 5, [ 6] = 6, [ 7] = 7, [ 8] = 8,
[ 9] = 9, [10] = 10, [11] = 11, [12] = 12, [13] = 13, [14] = 14, [15] = 15, [16] = 16,
Reconstructed Row-Major Matrix (6x6) 1-based:
r = 1: { 1 2 0 0 0 0 }
r = 2: { 3 4 5 0 0 0 }
r = 3: { 0 6 7 8 0 0 }
r = 4: { 0 0 9 10 11 0 }
r = 5: { 0 0 0 12 13 14 }
r = 6: { 0 0 0 0 15 16 }
Tridiagonal matrix X (6x6) 0-based:
c = 0 1 2 3 4 5
r = 0: { 1 2 0 0 0 0 }
r = 1: { 3 4 5 0 0 0 }
r = 2: { 0 6 7 8 0 0 }
r = 3: { 0 0 9 10 11 0 }
r = 4: { 0 0 0 12 13 14 }
r = 5: { 0 0 0 0 15 16 }
Vector Z (16) 0-based:
[ 0] = 1, [ 1] = 3, [ 2] = 2, [ 3] = 4, [ 4] = 6, [ 5] = 5, [ 6] = 7, [ 7] = 9,
[ 8] = 8, [ 9] = 10, [10] = 12, [11] = 11, [12] = 13, [13] = 15, [14] = 14, [15] = 16,
Reconstructed Column-Major Matrix (6x6) 0-based:
r = 0: { 1 2 0 0 0 0 }
r = 1: { 3 4 5 0 0 0 }
r = 2: { 0 6 7 8 0 0 }
r = 3: { 0 0 9 10 11 0 }
r = 4: { 0 0 0 12 13 14 }
r = 5: { 0 0 0 0 15 16 }
Tridiagonal matrix X (6x6) 1-based:
c = 1 2 3 4 5 6
r = 1: { 1 2 0 0 0 0 }
r = 2: { 3 4 5 0 0 0 }
r = 3: { 0 6 7 8 0 0 }
r = 4: { 0 0 9 10 11 0 }
r = 5: { 0 0 0 12 13 14 }
r = 6: { 0 0 0 0 15 16 }
Vector Z (16) 1-based:
[ 1] = 1, [ 2] = 3, [ 3] = 2, [ 4] = 4, [ 5] = 6, [ 6] = 5, [ 7] = 7, [ 8] = 9,
[ 9] = 8, [10] = 10, [11] = 12, [12] = 11, [13] = 13, [14] = 15, [15] = 14, [16] = 16,
Reconstructed Column-Major Matrix (6x6) 1-based:
r = 1: { 1 2 0 0 0 0 }
r = 2: { 3 4 5 0 0 0 }
r = 3: { 0 6 7 8 0 0 }
r = 4: { 0 0 9 10 11 0 }
r = 5: { 0 0 0 12 13 14 }
r = 6: { 0 0 0 0 15 16 }
Assuming d is the main diagonal, a is the "above" diagonal, and b is the "below" diagonal:
+---+---+---+---+---+---+---+---+
| d | a | 0 | 0 | 0 | 0 | 0 | 0 |
+---+---+---+---+---+---+---+---+
| b | d | a | 0 | 0 | 0 | 0 | 0 |
+---+---+---+---+---+---+---+---+
| 0 | b | d | a | 0 | 0 | 0 | 0 |
+---+---+---+---+---+---+---+---+
| 0 | 0 | b | d | a | 0 | 0 | 0 |
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | b | d | a | 0 | 0 |
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 | b | d | a | 0 |
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 | 0 | b | d | a |
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 | 0 | 0 | b | d |
+---+---+---+---+---+---+---+---+
Note that the problem assumes indexes are "origin 1" (e.g. 1 <= i <= n) but C arrays want "origin 0" (e.g. 0 <= i < n)
We can use an "inner" struct to represent the Y array (e.g. elem_t) and the basic functions are:
#include <stdio.h>
#include <stdlib.h>
// sparse matrix Y vector
typedef struct {
int a; // above diagonal
int d; // main diagonal
int b; // below diagonal
} elem_t;
// sparse matrix
typedef struct {
int n;
elem_t *base;
} sparse_t;
// sparse_create -- create sparse tridiagonal matrix
sparse_t *
sparse_create(int n)
{
sparse_t *mtx = malloc(sizeof(*mtx));
mtx->n = n;
mtx->base = calloc(n,sizeof(*mtx->base));
return mtx;
}
// sparse_pointer -- point to sparse matrix element
int *
sparse_pointer(sparse_t *mtx,int coli,int rowi)
{
int n = mtx->n;
elem_t *eptr;
int *iptr = NULL;
// convert to origin 0
coli -= 1;
rowi -= 1;
do {
// check column bounds
if (coli < 0)
break;
if (coli >= n)
break;
// check row bounds
if (rowi < 0)
break;
if (rowi >= n)
break;
eptr = &mtx->base[coli];
// main diagonal
if (rowi == coli) {
iptr = &eptr->d;
break;
}
// above diagnonal
if ((rowi == (coli - 1)) && (coli > 0)) {
iptr = &eptr->a;
break;
}
// below diagnonal
if ((rowi == (coli + 1)) && (coli < (n - 1))) {
iptr = &eptr->b;
break;
}
} while (0);
return iptr;
}
// sparse_getval -- get matrix value
int
sparse_getval(sparse_t *mtx,int coli,int rowi)
{
int *iptr = sparse_pointer(mtx,coli,rowi);
int val;
if (iptr != NULL)
val = *iptr;
else
val = 0;
return val;
}
// sparse_setval -- set matrix value
void
sparse_setval(sparse_t *mtx,int coli,int rowi,int val)
{
int *iptr = sparse_pointer(mtx,coli,rowi);
if (iptr != NULL)
*iptr = val;
}
By contrast, a regular/full matrix would be:
#include <stdio.h>
#include <stdlib.h>
// regular/full matrix
typedef struct {
int n;
int *base;
} regmtx_t;
// regmtx_create -- create regular matrix
regmtx_t *
regmtx_create(int n)
{
regmtx_t *mtx = malloc(sizeof(*mtx));
mtx->n = n;
mtx->base = calloc(n * n,sizeof(*mtx->base));
return mtx;
}
// regmtx_pointer -- point to regular matrix element
int *
regmtx_pointer(regmtx_t *mtx,int coli,int rowi)
{
int *iptr = NULL;
// convert to origin 0
coli -= 1;
rowi -= 1;
do {
// check column bounds
if (coli < 0)
break;
if (coli >= mtx->n)
break;
// check row bounds
if (rowi < 0)
break;
if (rowi >= mtx->n)
break;
iptr = &mtx->base[(coli * mtx->n) + rowi];
} while (0);
return iptr;
}

recursion - data structure course - print all possible series

I need to print all possible series that their sum is equal to N;
for example is n == 4 the output should be:
[1, 1, 1, 1]
[1, 1, 2]
[1, 2, 1]
[1, 3]
[2, 1, 1]
[2, 2]
[3, 1]
[4]
My way of thinking to solve this problem was:
print the series that the number i is not in the series
print the series that the number i is in the series, now need to find the sum of N-i.
my code:
#include <stdio.h>
#include <stdlib.h>
void printArr(int arr[], int n)
{
for (int i = 0; i < n; i++)
{
printf(" %d ", arr[i]);
}
printf("\n");
}
void printAllHelper(int* a,int size, int sum, int used,int index) {
if (sum == 0) {
a -= used;
printArr(a, used);
}
else if (sum < 0 || index == size)
{
return;
}
else {
for(int i = 1 ; i <= size ; i ++)
{
printAllHelper(a, size, sum, used, index + 1);
if (i <= sum)
{
*a = i;
}
printAllHelper(a+1, size, sum -i, used +1, index + 1);
}
}
}
void printAll(int num) {
int* myArray = (int*)malloc(num * sizeof(int));
printAllHelper(myArray,num,num,0,0);
}
void main() {
printAll(4);
}
my output:
3 1
3 1
3 1
3 1
3 1
3 1
3 1
3 1
3 1
4
1 3
4
2 2
4
3 1
4
4
1 3
1 1 2
1 3
1 2 1
1 3
1 3
1 3
4
1 3
4
2 2
4
3 1
4
4
2 2
2 1 1
2 2
2 2
2 2
2 2
4
1 3
4
2 2
4
3 1
4
4
3 1
3 1
3 1
3 1
3 1
4
1 3
4
2 2
4
3 1
4
4
4
4
Please try to explain to me your way of thinking, and how you approach this kind of problem, I want to be the very best like no one ever was :(.....
Your reasoning is not quite correct, but your code is almost right. The loop in your else part should be
for(int i = 1 ; i <= sum ; i ++) {
*a = i;
printAllHelper(a+1, size, sum-i, used+1, index+1);
}
With this, I get the output
1 1 1 1
1 1 2
1 2 1
1 3
2 1 1
2 2
3 1
4
The idea is basically: "The numbers sum to sum if the first number i is any number from 1 to sum and the rest of the numbers sum to sum - i."
Also, note that your code shows some room for improvement, e.g. the used and index variables seem a bit redundant. And with not adding numbers larger than sum or smaller than 1, the check whether sum < 0 || index == size is not necessary, either. Thus you also do not need the size parameter. Your printAllHelper could be simplified to something like this:
void printAllHelper(int* a, int sum, int index) {
if (sum == 0) {
printArr(a, index);
} else {
for(int i = 1 ; i <= sum ; i++) {
a[index] = i;
printAllHelper(a, sum-i, index+1);
}
}
}
(Note: C is not my native language, if you see more things to improve, please comment.)

Counting the number of elements of blocks with same consecutive elements

I'm having the following problem:
A park that have the form of a m x n board. There are k kinds of trees (1 <= k <= 100). The park is divided into m x n cells and each cell, they'll plant a tree. Now, on the map, each cell of the park have an integer i inside if the i-th kind of tree is planted in it, or a 0 if no tree is planted in it. A line of cells is considered "good" if it has at least t trees of same types, (and they must be on the same either line or column). Count the number of trees that is not in a "good" line.
Input: Integers m, n, t and an m x n array of integers represent the map.
Output: Number of trees that is not in a "good" line.
Example:
Input:
5 6 3
1 3 3 3 3 4
1 2 3 2 0 4
3 2 2 2 4 4
1 0 0 2 4 0
1 2 3 0 4 4
Output: 10
Explanation: The bold numbers are the trees that is not in a good line.
1 3 3 3 3 4
1 2 3 2 0 4
3 2 2 2 4 4
1 0 0 2 4 0
1 2 3 0 4 4
My idea is to check for each element in the array. If it is satisfied then I'll move to the nearest element outside the "good" line. Else, it will just move to the next element on the same line, or if the line is ended then the next element on the column.
Here is my code
#include <stdio.h>
#define maxn 120
int a[maxn][maxn], m, n, t;
int check(int *i, int *j){
int k, cnt_r, cnt_c;
cnt_r = 0;
//jump to the nearest cell that is not in good line
for(k = *i + 1; k < m; k++){
if(a[*i][*j] == a[k][*j]) cnt_r++;
if(cnt_r >= t){
*i = k;
return 1;
}
}
cnt_c = 0;
for(k = *j + 1; k < n; k++){
if(a[*i][*j] == a[*i][k]) cnt_c++;
if(cnt_c >= t){
*j = k;
return 1;
}
}
return 0;
}
//check if this is the last square or not
int lastSq(int r, int c){
return (r == n - 1 && c == n);
}
int main(){
int res = 0, i, j, pos_r = 0, pos_c = 0;
scanf("%d%d%d", &m, &n, &t);
for(i = 0; i < m; i++)
for(j = 0; j < n; j++)
scanf("%d", &a[i][j]);
while(!lastSq(pos_r, pos_c)){
if(a[pos_r][pos_c] == 0){
if(pos_c < n - 1) pos_c++;
else if(pos_r < n - 1){
pos_c = 0;
pos_r++;
}
}
if(!check(&pos_r, &pos_c)){
res++;
if(pos_c < n - 1) pos_c++;
else{
pos_c = 0;
pos_r++;
}
}
}
printf("%d", res);
}
But it doesn't print any output. The only thing I have is 0xC0000005. Can someone please check where did I make a mistake and provide me a direction? Thanks.

A bug on bubble sorting

I want to sort a 2*n matrix, n is given in the input. Make a program to output a matrix. Here is the requirement:
the first column MUST be sorted in ASC, and
the second column in DESC if possible.
For example, let n = 5, and the matrix is
3 4
1 2
3 5
1 6
7 3
The result should be
1 6
1 2
3 5
3 4
7 3
So I write down the code like this. First line input the value n, and the following lines like above.
#include <stdio.h>
#define TWO_16 65536
#define TWO_15 32768
int v[100000][2];
int z[100000];
int vec[100000];
int n;
int main()
{
int i, j;
scanf ("%d", &n); // give the value of n;
for (i = 1; i <= n; i++) // filling the matrix;
{
scanf ("%d%d", &v[i][0], &v[i][1]);
z[i] = TWO_16 * v[i][0] + TWO_15 - v[i][1];
vec[i] = i;
}
for (i = 1; i <= n; i++)
for (j = 1; j <= i; j++)
{
if (z[j] > z[i])
{
int t = vec[i];
vec[i] = vec[j];
vec[j] = t;
}
}
for (i = 1; i <= n; i++) // output the matrix
printf("%d %d\n",v[vec[i]][0],v[vec[i]][1]);
return 0;
}
But in gcc, the output is
1 6
3 5
3 4
1 2
7 3
What's more, when the first line is changed to "1 2" and the second is changed to "3 4" in input, the result also changed.
What's the problem of my code?
Additional information:
I use z[] because I use a function that satisfy the requirement of this problem, so I can simply sort them. And vec[] stores the original index, because moving arrays may cost lots of time. So v[vec[i]][0] means the 'new' array's item i.
Note that v[0] is NOT used. n is less than 100000, not equal.
You are comparing values stored in z[], but swapping elements of vec.
So when in the begginig you have:
i vec z
------------------
1 1 z[1]
2 2 z[2]
3 3 z[3]
...
After for e.g. swapping 2 with 3
i vec z
------------------
1 1 z[1]
2 3 z[2]
3 2 z[3]
...
you will have improper mapping between vec and z.
So in another iteration you will again compare z[2] with z[3] and again you will have to swap elements of vec. That's why you should at least also swap elements of z or index elements of z using elements of vec
i vec z
------------------
1 1 z[vec[1]] = z[1]
2 3 z[vec[2]] = z[3]
3 2 z[vec[3]] = z[2]
...
Adding this should do the trick
...
int t = vec[i];
vec[i] = vec[j];
vec[j] = t;
//Add this also when swapping vec
t = z[i];
z[i] = z[j];
z[j] = t;
...
Array index start with 0, so your for cicles must start from 0
if (z[j] > z[i]): you want to sort v but you are comparing z and sorting vec. By sorting vec and comparing z bubble sort cannot work. You must use the same array.

Optimize a summing of array (subset problem)

In the hottest part of my program (90% of time according to gprof), I need to sum one array A into another B. Both arrays are 2^n (n is 18..24) sized and holds an integer (for simplicity, actually the element stored is mpz_t or small int array). The rule of summing: for each i in 0..2^n-1, set B[i] = sum (A[j]), where j is bit vector, and j & ~ i == 0 (in other words, k-th bit of any j can't be set to 1 if k-th bit of i is not 1).
My current code (this is a body of innermost loop) does this in the time of 2^(1.5 * n) sums, because I will iterate for each i on (in average) 2^(n/2) elements of A.
int A[1<<n]; // have some data
int B[1<<n]; // empty
for (int i = 0; i < (1<<n); i++ ) {
/* Iterate over subsets */
for (int j = i; ; j=(j-1) & i ) {
B[i] += A[j]; /* it is an `sum`, actually it can be a mpz_add here */
if(j==0) break;
}
}
My I mentioned, that almost any sum is recomputed from the values, summed earlier. I suggest, there can be code, doing the same task in the time of n* 2^n sums.
My first idea is that B[i] = B[i_without_the_most_significant_bit] + A[j_new]; where j_new is only j's having the most_significant bit from i in '1' state. This halves my time, but this is not enough (still hours and days on real problem size):
int A[1<<n];
int B[1<<n];
B[0] = A[0]; // the i==0 will not work with my idea and clz()
for (int i = 1; i < (1<<n); i++ ) {
int msb_of_i = 1<< ((sizeof(int)*8)-__builtin_clz(i)-1);
int i_wo_msb = i & ~ msb;
B[i] = B[i_wo_msb];
/* Iterate over subsets */
for (int j_new = i; ; j_new=(j_new-1) & i ) {
B[i] += A[j_new];
if(j_new==msb) break; // stop, when we will try to unset msb
}
}
Can you suggest better algorithm?
Additional image, list of i and j summed for each i for n=4:
i j`s summed
0 0
1 0 1
2 0 2
3 0 1 2 3
4 0 4
5 0 1 4 5
6 0 2 4 6
7 0 1 2 3 4 5 6 7
8 0 8
9 0 1 8 9
a 0 2 8 a
b 0 1 2 3 8 9 a b
c 0 4 8 c
d 0 1 4 5 8 9 c d
e 0 2 4 6 8 a c e
f 0 1 2 3 4 5 6 7 8 9 a b c d e f
Note the similarity of figures
PS the msb magic is from here: Unset the most significant bit in a word (int32) [C]
Divide and conquer anyone? Now not in-place.
void sums(int *a, int n, int *b) {
if (n <= 0) {
*b = *a;
return;
}
int m = 1 << (n - 1);
sums(a, n - 1, b);
sums(a + m, n - 1, b + m);
for (int i = 0; i < m; i++) {
b[m + i] += b[i];
}
}

Resources