how to print a matrix with a negated row more efficiently - c

I wrote the following function:
void negate_row(const int n, const int r, int *a)
{
if (r == 0)
{
printf("Matrix with negated row: ");
printf("\n");
for (int y = 0; y < 3; y++)
{
*(a + 3 * r + y) = *(a + 3 * r + y) *(-1);
printf("%d ", *(a + 3 * r + y));
}
printf("\n");
for (int y = 0; y < 3; y++)
{
*(a + 3 * r + y) = *(a + 3 * r + y) *(-1);
printf("%d ", *(a + 3 * (r + 1) + y));
}
printf("\n");
for (int y = 0; y < 3; y++)
{
*(a + 3 * r + y) = *(a + 3 * r + y) *(-1);
printf("%d ", *(a + 3 * (r + 2) + y));
}
printf("\n");
}
So basically what happens here is my function takes in a n X 3 matrix and negates a specific row using pointer arithmetic. I have been able to achieve that, I've also been able to figure out how to print that same matrix with the negated row. It's just the way I'm doing it is not efficient at all. I'd have to write an if statement for each row, ex if r == 0,1,2,3,4 etc... is there any way I can do this more efficiently?
Some clarifications: const int n decides the size of the matrix (n x 3), const int r decides what row is negated (0 <= r < n).

A second loop will help. I generally find pointer code a bit harder to read. Particularly with Matrix manipulation you might be better off using array syntax instead of pointer syntax.
for (int y = 0; y < 3; y++)
{
for (int x = 0; x < 3; x++)
{
printf("%d ", *(a + 3 * (r + x) + y));
}
printf("\n");
}

Particular case (3 rows):
int mul = 1, y = 0;
for (int x = 0; x < n; x++) {
mul = x == r ? -1 : 1;
y = (a + 3 * x);
printf("%d ", (*y) * mul);
printf("%d ", (*y + 1) * mul);
printf("%d ", (*y + 2) * mul);
printf("\n");
}
More generic (m rows):
int mul = 1;
for (int x = 0; x < n; x++) {
mul = x == r ? -1 : 1;
for (int y = 0; y < m; y++) {
printf("%d ", ((*(a + m * x + y)) * mul);
}
printf("\n");
}
Note: In new compilers there is also no difference in speed between array or pointer syntax.

You could write a function that accepts a one-dimensional array (a row of your matrix) and then using this function you could in a loop output its all rows or output a selected row.
Here is a demonstrative program.
#include <stdio.h>
void negate_row( const int *a, size_t n, int width )
{
if ( width < 1 ) width = 1;
for ( const int *p = a; p != a + n; ++p )
{
printf( "%*d ", width, -*p );
}
putchar( '\n' );
}
int main(void)
{
enum { M = 3, N = 4 };
int matrix[M][N] =
{
{ 0, 1, 2, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 }
};
for ( int ( *p )[N] = matrix; p != matrix + M; ++p )
{
negate_row( *p, N, 3 );
}
return 0;
}
The program output is
0 -1 -2 -4
-5 -6 -7 -8
-9 -10 -11 -12
As you showed a code where you are using pointers tp output elements of an array then in this demonstrative program I am also using pointers everywhere to access elements of an array.
The third parameter of the function specifies the width of the field for an outputted value.
To output the matrix in the reversed order of rows you can use the loop shown in the program blow.
#include <stdio.h>
void negate_row( const int *a, size_t n, int width )
{
if ( width < 1 ) width = 1;
for ( const int *p = a; p != a + n; ++p )
{
printf( "%*d ", width, -*p );
}
putchar( '\n' );
}
int main(void)
{
enum { M = 3, N = 4 };
int matrix[M][N] =
{
{ 0, 1, 2, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 }
};
for ( int ( *p )[N] = matrix + M; p != matrix; )
{
negate_row( *--p, N, 3 );
}
return 0;
}
The program output is
-9 -10 -11 -12
-5 -6 -7 -8
0 -1 -2 -4

You can generalize the function easily: as long as the row is within the matrix, your code works for any row. Also note that it is better to use a separate function to print the matrix.
#include <stdio.h>
void negate_row(const int n, const int r, int *a) {
if (r >= 0 && r < n) {
// negate row r
for (int col = 0; col < 3; col++) {
*(a + 3 * r + col) *= -1;
}
}
}
void print_matrix(const int n, int *a, const char *title) {
if (title) {
printf("%s:\n", title);
}
for (int row = 0; row < n; row++) {
for (int col = 0; col < 3; col++) {
printf("%d ", *(a + 3 * row + col));
}
printf("\n");
}
printf("\n");
}
int main() {
int matrix[5 * 3] = {
0, 1, 2,
3, 4, 5,
6, 7, 8,
9, 10, 11,
12, 13, 14,
};
print_matrix(5, matrix, "Matrix");
negate_row(5, 0, matrix);
print_matrix(5, matrix, "Matrix with negated row");
negate_row(5, 3, matrix);
print_matrix(5, matrix, "Matrix with two negated rows");
negate_row(5, 0, matrix);
negate_row(5, 3, matrix);
print_matrix(5, matrix, "Matrix back to origin");
return 0;
}
Output:
Matrix:
0 1 2
3 4 5
6 7 8
9 10 11
12 13 14
Matrix with negated row:
0 -1 -2
3 4 5
6 7 8
9 10 11
12 13 14
Matrix with two negated rows:
0 -1 -2
3 4 5
6 7 8
-9 -10 -11
12 13 14
Matrix back to origin:
0 1 2
3 4 5
6 7 8
9 10 11
12 13 14

Related

Weird behavior with C array

I have two arrays A and B both with the same elements { 1, 2, 3, 4 } but after doing A[B[i]] = A[i] + 1 array B is getting populated with different number but in reality it should be unchanged.
#include <stdio.h>
void arrayPrint(int *arr, int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int A[4] = { 1, 2, 3, 4 };
int B[4] = { 1, 2, 3, 4 };
int n = 3;
printf("Before \n");
printf("Array A \n");
arrayPrint(A, 4);
printf("Array B \n");
arrayPrint(B, 4);
for (int i = 0; i <= n; i++) {
if (A[i] == B[i]) {
A[B[i]] = A[i] + 1;
}
}
printf("\nAfter \n");
printf("Array A \n");
arrayPrint(A, 4);
printf("Array B \n");
arrayPrint(B, 4);
return 0;
}
Output is:
Before
Array A
1 2 3 4
Array B
1 2 3 4
After
Array A
1 2 3 4
Array B
5 2 3 4
but it should be:
Before
Array A
1 2 3 4
Array B
1 2 3 4
After
Array A
1 2 3 4
Array B
1 2 3 4
For B[i] equal to 4 the expression A[B[i]] access memory beyond the array A because the valid range of indices for the array A is [0, 3].
So it seems the compiler placed the array B at once after the array A and the first element of the array B was changed in this statement
A[B[i]] = A[i] + 1;
for i equal to 3.
Instead of your for loop
for (int i = 0; i <= n; i++) {
if (A[i] == B[i]) {
A[B[i]] = A[i] + 1;
}
}
you could write for example
for (int i = 0; i <= n; i++) {
if ( i != 3 && A[i] == B[i]) {
A[B[i]] = A[i] + 1;
}
}
Or more precisely
const size_t N = sizeof( A ) / sizeof( *A );
for (int i = 0; i <= n; i++) {
if ( i != N - 1 && A[i] == B[i]) {
A[B[i]] = A[i] + 1;
}
}
In last iteration of the for loop, i has the value 3, so A[B[i]] = A[i] + 1; evaluates as A[4] = A[3] + 1;.
Storing anything into A[4] has undefined behavior. What you observe is consistent with the array B being placed in memory immediately after array A but this is by no means guaranteed by the C Standard. The behavior is just undefined and anything can happen.

Quicksort skipping one element

So today i tried to implement a quicksort. It's almost working but somehow skips one element.
example : 5 2 8 2 3 4 1 5 7 -5 -1 -9 2 4 5 7 6 1 4
output : -5 -1 -9 1 2 2 3 2 1 4 4 4 5 5 5 6 7 7 8
In this case it skips -9. Here is code of the function.
test = quicksort_asc(0,size,tab,size) // this is function call
int quicksort_asc(int l, int r, int tab[], int tabSize) //l is first index, r is last index, tabSize is tabsize-1 generally
{
int i,buffer,lim,pivot,flag=0;
if(l == r)
return 0;
lim = l-1;
pivot = tab[r-1];
printf("pivot:%d\n",pivot);
for (i = l; i <= r-1; ++i)
{
if(tab[i] < pivot) {
lim++;
buffer = tab[lim];
tab[lim] = tab[i];
tab[i] = buffer;
flag = 1;
}
}
if(flag == 0)
return 0;
buffer = tab[lim+1];
tab[lim+1] = pivot;
tab[r-1] = buffer;
quicksort_asc(l,lim+1,tab,lim+1);//left side
quicksort_asc(lim+1,tabSize,tab,tabSize);//right side
}
This is my array length count code. 100 is maximum size, 0 is a stop value.
Count is size.
int count=0;
for (int i = 0; i < 100; i++)
{
test = scanf("%d",&vec[i]);
if(vec[i] == 0) break;
count++;
}
return count;
It seems nobody hurries to help you.:)
For starters the last parameter is redundant.
int quicksort_asc(int l, int r, int tab[], int tabSize);
^^^^^^^^^^^
All you need is the pointer to the first element of the array and starting and ending indices.
Also instead of the type int for the indices it is better to use the type size_t. However as you are using the expression statement
lim = l-1;
then o'k let the indices will have the type int though you could use another approach without this expression statement.
So the function should be declared like
void quicksort_asc( int tab[], int l, int r );
The variable flag is redundant. When it is equal to 0 it means that all elements before the pivot value are greater than or equal to it. But nevertheless you have to swap the pivot value with the first element that is greater than or equal to the pivot.
This loop
for (i = l; i <= r-1; ++i)
has one iteration redundant. It should be set like
for (i = l; i < r-1; ++i)
This call
quicksort_asc(lim+1,tabSize,tab,tabSize);
^^^^^ ^^^^^^^
shall be substituted for this call
quicksort_asc( lim + 2, r, tab );
^^^^^^^ ^^
because the pivot value is not included in this sub-array.
Here is a demonstrative program.
#include <stdio.h>
void quicksort_asc( int tab[], int l, int r )
{
if ( l + 1 < r )
{
int lim = l - 1;
int pivot = tab[r - 1];
for ( int i = l; i < r - 1; ++i )
{
if ( tab[i] < pivot )
{
lim++;
int tmp = tab[lim];
tab[lim] = tab[i];
tab[i] = tmp;
}
}
tab[r - 1] = tab[lim + 1];
tab[lim + 1] = pivot;
quicksort_asc( tab, l, lim + 1 );
quicksort_asc( tab, lim + 2, r );
}
}
int main(void)
{
int a[] = { 5, 2, 8, 2, 3, 4, 1, 5, 7, -5, -1, -9, 2, 4, 5, 7, 6, 1, 4 };
const int N = ( int )( sizeof( a ) / sizeof( *a ) );
for ( int i = 0; i < N; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
quicksort_asc( a, 0, N );
for ( int i = 0; i < N; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
return 0;
}
Its output is
5 2 8 2 3 4 1 5 7 -5 -1 -9 2 4 5 7 6 1 4
-9 -5 -1 1 1 2 2 2 3 4 4 4 5 5 5 6 7 7 8

Split digits in array [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I'm totally beginner and I have problem in C. So I have array:
A[5] = {14, 2, 7, 3, 2};
And I want make something like this:
A[6] = {1, 4, 2, 7, 3, 2};
From 14 to 1, 4. Any idea how to do that?
So I making the problem from Cs50. Here is a link: https://docs.cs50.net/2018/x/psets/1/credit/credit.html
And here is my code:
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <math.h>
int main(void)
{
long long cc_number = 0;
do
{
printf("Number: ");
cc_number = get_long_long();
}
while(cc_number <= 0);
int num_of_digits = 0;
long long valid = cc_number;
while(valid > 0)
{
valid /= 10;
num_of_digits++;
}
if (num_of_digits != 13 && num_of_digits != 15 && num_of_digits != 16 ) //checking if number have more or less than 13,15,16 digits
{
printf("Number is invalid!\n");
}
long long k = 1; //create array for store each number from the card
int A[16], d, num = 0;
for(num = 0; num < 16; num++)
{
d = (cc_number/(1*k)) % 10;
A[num] = d;
k *=10;
}
///////////////////////////////////////////////////////////////////////
if (num_of_digits == 16)
{
for (int i = 0; i < 16; i = i + 2)
{
A[i] *= 2; // multiplay each second digit by 2
printf("this is %i\n", A[i]);
}
}
else if (num_of_digits == 15 || num_of_digits == 13 )
{
int sum = 0;
for (int i = 1; i < 15; i = i + 2)
{
int y = A[i];
A[i] *= 2; // multiplay each second digit by 2
if (A[i] > 9) // try to split digit from array
{
y = A[i] % 10;
A[i] /= 10;
}
sum += A[i];
printf("this is %i\n", A[i]);
}
printf("this is sum %i\n", sum);
}
///////////////////////////////////////////////////////////////////////////
}
And this is what i want to do:
For the sake of discussion, let’s first underline every other digit,
starting with the number’s second-to-last digit:
378282246310005
Okay, let’s multiply each of the underlined digits by 2:
7•2 + 2•2 + 2•2 + 4•2 + 3•2 + 0•2 + 0•2
That gives us:
14 + 4 + 4 + 8 + 6 + 0 + 0
Now let’s add those products' digits (i.e., not the products themselves) together:
1 + 4 + 4 + 4 + 8 + 6 + 0 + 0 = 27
Now let’s add that sum (27) to the sum of the digits that weren’t multiplied by 2:
27 + 3 + 8 + 8 + 2 + 6 + 1 + 0 + 5 = 60
Yup, the last digit in that sum (60) is a 0, so my card is legit!
Assuming you want to create an array of single digit integers from array of multi-digit integers
#include <stdio.h>
#define MAX 1024
void printarr(int *a, int n) { // function to print array
for(int i = 0; i < n; i++) {
printf("%d ", a[i]);
}
printf("\n");
}
int main() {
int a[5] = {14, 2, 7, 3, 2};
int b[MAX];
int k = 0;
printarr(a, 5);
char s[MAX]; // char buffer to store char array
for(int i = 0; i < 5; i++) {
sprintf(s, "%d", a[i]);// convert int to char array
int j = 0;
while(s[j]!='\0') { // for each digit, create a new integer
b[k++] = s[j++] - '0';
}
}
printarr(b, k);
return 0;
}
Output:
14 2 7 3 2
1 4 2 7 3 2
Else for specific case
#include <stdio.h>
#define MAX 1024
void printarr(int *a, int n) { // function to print array
for(int i = 0; i < n; i++) {
printf("%d ", a[i]);
}
printf("\n");
}
int main() {
int a[5] = {14, 2, 7, 3, 2};
int b[6];
printarr(a, 5);
b[0] = 1;
b[1] = 4;
for(int i = 2; i < 6; i++) {
b[i] = a[i - 1];
}
printarr(b, 6);
return 0;
}
Output:
14 2 7 3 2
1 4 2 7 3 2
Here is a solution that does not use strings.
First of all, we have to determine how long the new array will be. To this end, we determine how many digits each entry has. For n > 0 the number of digits is ⌊log10(n) + 1⌋.
After that, we extract the digits. 123 can be split into its digits by using integer division / and modulo % (remainder of integer division):
123 % 10 = 3 least significant digit
123 / 10 = 12
repeat
12 % 10 = 2 second least significant digit
12 / 10 = 1
repeat
1 % 10 = 1 third least significant digit
1 / 10 = 0
end
As you can see, the digits are extracted from the back, therefore we also fill the output array from the back.
#include <stdio.h>
#include <math.h>
int digitCount(int n) {
if (n)
return (int) log10(n) + 1;
return 1;
}
int main() {
int inputLength = 5;
int input[] = {14, 1, 9, 0, 5819};
int outputLength = 0;
for (int i = 0; i < inputLength; ++i)
outputLength += digitCount(input[i]);
int output[outputLength];
int o = outputLength;
for (int i = inputLength - 1; i >= 0; --i) {
int n = input[i];
do {
output[--o] = n % 10;
n /= 10;
} while (n);
}
while (o < outputLength) {
printf("%d ", output[o++]);
}
}
clang -lm file.c && ./a.out prints 1 4 1 9 0 5 8 1 9.

matrix rotation..for loop changes the value of pointer

In the final value of array only first element becomes zero and that too when it again goes to the for loop(checked using gdb)..i have mentioned the problem using comments at the bottom of code.Help me out.. I have no clue of what is going wrong.
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a, b, c;
printf("enter the size of matrix");
scanf("%d%d",&a,&b);
printf("enter the number of rotations");
scanf("%d",&c);
int *arr = malloc (sizeof(int) * a * b);
int x = (a >= b)? a : b;
printf("enter the values of matrix");
// scanning the values
for(int i = 0; i < a; i++)
{
for(int j = 0; j < b; j++)
{
scanf("%d",(arr + i * b + j));
}
printf("\n");
}
// main code starts
for(int y = 0; y < c; y++)
{
// declared a new array
int *arr1 = malloc (sizeof(int) * a * b);
for(int k = 0; k < x / 2; k++)
{
for(int i = k; i < a - k; i++)
{
for(int j = k; j < b - k; j++)
{
if (i == k && j > k)
{
*(arr1 + i * b + j - 1) = *(arr + i * b + j);
}
else if (i == a - k - 1 && j < b - k - 1)
{
*(arr1 + i * b + j + 1) = *(arr + i * b + j);
}
else if (j == k && i < a - k - 1)
{
*(arr1 + i * b + j + b) = *(arr + i * b + j);
}
else if (j == b - k - 1 && i > k)
{
*(arr1 + i * b + j - b) = *(arr + i * b + j);
}
}
}
if (x % 2 != 0 && a == b)
*(arr1 + x / 2 * b + (b / 2)) = *(arr + x / 2 * b + (b / 2));
}
// changing the old array to new array
arr = arr1;
// first value is getting printed correctly here
printf("%d\n",*(arr));
printf("%p\n",&(*arr));
free(arr1);
}
// printing the output
for(int i = 0; i < a; i++)
{
for(int j = 0; j < b; j++)
{
printf("%d ",*(arr + i * b + j));
}
printf("\n");
}
// first value is getting printed incorrectly here, outside the loop
printf("\n%d\n",*(arr));
printf("%p",&(*arr));
}
C doesn't support array assignment. You have:
int *arr = malloc (sizeof(int) * a * b);
…
int *arr1 = malloc (sizeof(int) * a * b);
…
arr = arr1;
…
free(arr1);
The assignment means you've lost your original array (memory leak) and you then invalidate your new array with the free().
Array copying requires more code — usually a function call such as memmove() or memcpy(), possibly wrapped in a function.
For example, add #include <string.h> and use this in place of the arr = arr1; assignment:
memmove(arr, arr1, sizeof(int) * a * b);
free(arr1); // No longer needed
Alternatively:
free(arr);
arr = arr1;
This code runs cleanly under valgrind on Mac OS X 10.11.5 with GCC 6.1.0 with the 'Either' or the 'Or' options for handling the array assignments.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void dump_matrix(const char *tag, int *arr, int a, int b)
{
printf("Matrix: %s\n", tag);
for (int i = 0; i < a; i++)
{
for (int j = 0; j < b; j++)
printf(" %3d", arr[i * b + j]);
putchar('\n');
}
}
int main(void)
{
int a, b, c;
printf("enter the size of matrix: ");
scanf("%d%d", &a, &b);
printf("enter the number of rotations: ");
scanf("%d", &c);
int *arr = malloc(sizeof(int) * a * b);
int x = (a >= b) ? a : b;
printf("enter the values of matrix: ");
// scanning the values
for (int i = 0; i < a; i++)
{
for (int j = 0; j < b; j++)
{
if (scanf("%d", (arr + i * b + j)) != 1)
{
fprintf(stderr, "failed to read value arr[%d][%d]\n", i, j);
return EXIT_FAILURE;
}
}
printf("\n");
}
dump_matrix("Initial input", arr, a, b);
// main code starts
for (int y = 0; y < c; y++)
{
// declared a new array
int *arr1 = malloc(sizeof(int) * a * b);
for (int k = 0; k < x / 2; k++)
{
for (int i = k; i < a - k; i++)
{
for (int j = k; j < b - k; j++)
{
if (i == k && j > k)
{
*(arr1 + i * b + j - 1) = *(arr + i * b + j);
}
else if (i == a - k - 1 && j < b - k - 1)
{
*(arr1 + i * b + j + 1) = *(arr + i * b + j);
}
else if (j == k && i < a - k - 1)
{
*(arr1 + i * b + j + b) = *(arr + i * b + j);
}
else if (j == b - k - 1 && i > k)
{
*(arr1 + i * b + j - b) = *(arr + i * b + j);
}
}
}
if (x % 2 != 0 && a == b)
*(arr1 + x / 2 * b + (b / 2)) = *(arr + x / 2 * b + (b / 2));
}
// Changing the old array to new array
// Either:
// memmove(arr, arr1, sizeof(int) * a * b);
// free(arr1);
// Or:
free(arr);
arr = arr1;
dump_matrix("After rotation", arr, a, b);
}
dump_matrix("Finished", arr, a, b);
free(arr);
return 0;
}
Note the use of the dump_matrix() function. Writing such a function once means it can be used multiple places in the code. The tag argument simplifies the use. The 'commercial grade' variant takes a FILE *fp argument too and writes to the specified file stream.
Note the error checking on the main input loop scanf(). I should also have checked the two other scanf() statements. Errors are reported on standard error, of course.
Example run:
$ ./mat31
enter the size of matrix: 3 4
enter the number of rotations: 2
enter the values of matrix: 1 2 3 4 10 11 12 13 99 98 97 96
Matrix: Initial input
1 2 3 4
10 11 12 13
99 98 97 96
Matrix: After rotation
2 3 4 13
1 12 11 96
10 99 98 97
Matrix: After rotation
3 4 13 96
2 11 12 97
1 10 99 98
Matrix: Finished
3 4 13 96
2 11 12 97
1 10 99 98
$
Whether the output is what you intended is a wholly separate discussion. This is simply not abusing the memory.

Finding all adjacent elements in a 2D array

I am working on a project where at one point I am stuck.
My question is for example I have the following 2D array containing 3 different integers.
2 2 2 2 1
1 2 2 2 1
3 3 2 3 2
3 1 3 3 1
1 1 2 3 1
1 3 1 3 3
What I want is to find the longest adjacent elements chain of array of any number contained in the array.
Like in the above array the longest chain is of digit 2.
2 2 2 2
2 2 2
2
Can anyone just guide me as to what I have to do to achieve this goal?
Easier to draw than to explain...
2 2 2 2 1 => A A A A B => (A: 4, B: 1)
1 2 2 2 1 => C A A A B => (A: 3 + 4, B: 1 + 1, C: 1)
3 3 2 3 2 => D D A E F => (A: 1 + 7, B: 2, C: 1, D: 2, E: 1, F: 1)
3 1 3 3 1 => D G E E G => (A: 8, B: 2, C: 1, D: 2 + 1, E: 2 + 1, F: 1, G: 1)
1 1 2 3 1 => ...
1 3 1 3 3 => ...
update:
And now, with some real code:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define ROWS 6
#define COLS 5
unsigned char eles[ROWS][COLS] = { { 2, 2, 2, 2, 1 },
{ 1, 2, 2, 2, 1 },
{ 3, 3, 2, 3, 2 },
{ 3, 1, 3, 3, 1 },
{ 1, 1, 2, 3, 1 },
{ 1, 3, 1, 3, 3 } };
struct zone {
int acu;
int row, col;
int refs;
};
typedef struct zone zone;
zone *
new_zone(int row, int col) {
zone *z = (zone *)malloc(sizeof(zone));
z->col = col;
z->row = row;
z->refs = 1;
z->acu = 0;
}
void croak (const char *str) {
fprintf(stderr, "error: %s\n", str);
exit(1);
}
void
free_zone(zone *z) {
if (z->refs != 0) croak("free_zone: reference count is not cero");
free(z);
}
zone *
ref_zone(zone *z) {
z->refs++;
return z;
}
void
unref_zone(zone *z) {
z->refs--;
if (!z->refs) free_zone(z);
}
int
main() {
zone *last[COLS];
zone *current[COLS];
zone *best = new_zone(0, 0);
int i, j;
memset(last, 0, sizeof(last));
for (j = 0; j < ROWS; j++) {
for (i = 0; i < COLS; i++) {
unsigned int ele = eles[j][i];
zone *z;
/* printf("analyzing ele: %d at row %d, col: %d\n", ele, j, i); */
if (i && (ele == eles[j][i-1])) {
/* printf(" equal to left element\n"); */
z = ref_zone(current[i-1]);
if (j && (ele == eles[j-1][i])) {
zone *z1 = last[i];
/* printf(" equal to upper element\n"); */
if (z != z1) {
int k;
/* printf(" collapsing zone %p\n", z1); */
z->acu += z1->acu;
for (k = 0; k < COLS; k++) {
if (last[k] == z1) {
last[k] = ref_zone(z);
unref_zone(z1);
}
}
for (k = 0; k < i; k++) {
if (current[k] == z1) {
current[k] = ref_zone(z);
unref_zone(z1);
}
}
}
}
}
else if (j && (ele == eles[j-1][i])) {
/* printf(" equal to upper element\n"); */
z = ref_zone(last[i]);
}
else {
/* printf(" new element\n"); */
z = new_zone(j, i);
}
z->acu++;
current[i] = z;
/* printf(" element zone: %p\n", z); */
}
for (i = 0; i < COLS; i++) {
if (j) unref_zone(last[i]);
last[i] = current[i];
if (best->acu < current[i]->acu) {
unref_zone(best);
best = ref_zone(current[i]);
/* printf("best zone changed to %p at row; %d, col: %d, acu: %d\n", best, best->row, best->col, best->acu); */
}
}
}
printf("best zone is at row: %d, col: %d, ele: %d, size: %d\n", best->row, best->col, eles[best->row][best->col], best->acu);
}
Suppose your matrix is a graph, and the elements are vertices. Two vertices are connected if they are adjacent and have the same value. If you perform any search in that graph, be it Breadth-First Search or Depth-First Search, you'll get exactly what you want. HTH
You could treat this like a picture in a paint application. Perform a flood-fill on each element in your 2D array (unless its filled already by something else) and keep track how many pixels you filled in each step.
If your array is declared like
int elements[5][5];
Then introduce a second array which tells whether you filled an element already (if you like, use a different type like bool if thats's okay in your C program):
int pixelFilled[5][5];
memset( pixelFilled, 0, sizeof( pixelFilled ) );
Next, write a recursive function which performs a flood fill and returns the numbers of elements which were filled (I'm writing this from the top of my head, no guarantee whatsoever that this function works as it is):
int floodFill( int x, int y ) {
int filledPixels = 0;
if ( !pixelFilled[x][y] ) {
++filledPixels;
pixelFilled[x][y] = 1;
} else {
return 0;
}
if ( x < 4 && elements[x+1][y] == elements[x][y] )
filledPixels += floodFill( x + 1, y );
if ( x > 0 && elements[x-1][y] == elements[x][y] )
filledPixels += floodFill( x - 1, y );
if ( y < 4 && elements[x][y+1] == elements[x][y] )
filledPixels += floodFill( x, y + 1 );
if ( y > 0 && elements[x][y-1] == elements[x][y] )
filledPixels += floodFill( x, y - 1 );
return filledPixels;
}
Finally, iterate over your array and try to fill it completely. Keep track of the largest filled array:
int thisArea = 0;
int largestArea = 0;
int x, y;
for ( y = 0; y < 5; ++y ) {
for ( x = 0; x < 5; ++x ) {
thisArea = floodFill( x, y );
if (thisArea > largestArea ) {
largestArea = thisArea;
}
}
}
Now, largestArea should contain the size of the longest chain of adjacent elements.
define another 2d array of the same size, initialize all cells to 0
set maxval to 0
if helper array is full of 1's go to 5, otherwise find a cell with 0 and do:
3.1 change value of the cell to 1
3.2 set a counter to 1
3.3 check all adjacent cells, if they're 0 in the helper array and the same value as current cell in the input array then counter++ and go to 2.1 with new coordinates.
maxval = max(maxval,counter), go to 3
return maxval
steps 3.1-3.3 should be implemented as a recursive function which takes coordinate and both arrays as arguments and returns 1+the sum of the returned values from the recursive calls.
I love this kind of problems :-) so here it is my answer.
As said by Frerich Raabe, this can be solved with a floodFill function. For example, opencv library would provide such a function off the shelf.
Please forgive me if in the following code you'll find traces of C++, in case they should be simple to be replaced.
typedef struct Point {
int x;
int y;
} Point;
int areaOfBiggestContiguousRegion(int* mat,int nRows, int nCols) {
int maxArea = 0;
int currValue, queueSize, queueIndex;
int* aux;
Point queue[1000]; //Stores the points I need to label
Point newPoint, currentPoint;
int x,y,x2,y2;
//Code: allocate support array aux of same size of mat
//Code: fill aux of zeros
for (y = 0; y < nRows; y++)
for (x = 0; x < nCols; x++)
if (aux[y * nCols + x] == 0) {//I find a pixel not yet labeled, my seed for the next flood fill
queueIndex = 0; //Contains the index to the next element in the queue
queueSize = 0;
currValue = mat[y * nCols + x]; //The "color" of the current spot
aux[y * nCols + x] = 1;
newPoint.x = x;
newPoint.y = y;
queue[queueSize] = newPoint;
queueSize++;
while(queueIndex != queueSize) {
currPoint = queue[queueIndex];
queueIndex++;
//Look left, right, up, down
x2 = currPoint.x - 1;
y2 = currPoint.y;
//Some copy & paste, sorry I have been too long on C++ to remember correctly about C functions
if (x2 >= 0 && aux[y2 * nCols + x2] == 0 && mat[y2 * nCols + x2] == currValue) {
aux[y2 * nCols + x2] = 1;
newPoint.x = x2;
newPoint.y = y2;
queue[queueSize] = newPoint;
queueSize++;
}
x2 = currPoint.x + 1;
y2 = currPoint.y;
//Some copy & paste, sorry I have been too long on C++ to remember correctly about C functions
if (x2 < nCols && aux[y2 * nCols + x2] == 0 && mat[y2 * nCols + x2] == currValue) {
aux[y2 * nCols + x2] = 1;
newPoint.x = x2;
newPoint.y = y2;
queue[queueSize] = newPoint;
queueSize++;
}
x2 = currPoint.x;
y2 = currPoint.y - 1;
//Some copy & paste, sorry I have been too long on C++ to remember correctly about C functions
if (y2 >= 0 && aux[y2 * nCols + x2] == 0 && mat[y2 * nCols + x2] == currValue) {
aux[y2 * nCols + x2] = 1;
newPoint.x = x2;
newPoint.y = y2;
queue[queueSize] = newPoint;
queueSize++;
}
x2 = currPoint.x;
y2 = currPoint.y + 1;
//Some copy & paste, sorry I have been too long on C++ to remember correctly about C functions
if (y2 < nRows && aux[y2 * nCols + x2] == 0 && mat[y2 * nCols + x2] == currValue) {
aux[y2 * nCols + x2] = 1;
newPoint.x = x2;
newPoint.y = y2;
queue[queueSize] = newPoint;
queueSize++;
}
} //while
if (queueSize > maxArea)
maxArea = queueSize; //If necessary we could store other details like currentValue
}//if (aux...
return maxArea;
}
Note: In C++ using std containers and a constructor for Point it becomes much more compact

Resources