Euler project problem 58, where's the error - c

I'm just not able to see where's the error on my code, I am getting 26249 (or 26247 if I go back one spiral level), but it should be 26241.
Obviously, there must be a problem with my logic, but I can't point out where.
Spiral Primes, Project Euler Problem 58
Starting with 1 and spiralling anticlockwise in the following way, a square spiral with side length 7 is formed.
37 36 35 34 33 32 31
38 17 16 15 14 13 30
39 18 05 04 03 12 29
40 19 06 01 02 11 28
41 20 07 08 09 10 27
42 21 22 23 24 25 2643 44 45 46 47 48 49
It is interesting to note that the odd squares lie along the bottom right diagonal, but what is more interesting is that 8 out of the 13 numbers lying along both diagonals are prime; that is, a ratio of 8/13 ≈ 62%.
If one complete new layer is wrapped around the spiral above, a square spiral with side length 9 will be formed. If this process is continued, what is the side length of the square spiral for which the ratio of primes along both diagonals first falls below 10%?
#include <stdio.h>
#define print(ref) printf(#ref" = %d\n",ref);
#define printl(ref) printf(#ref" = %ld\n",ref);
#define NUM_OF_PRIMES 5000
int primesOnThisLevel(int);
void generatePrimes();
int isPrime(int);
int canBeExpressedAsPrime(int);
int primes[NUM_OF_PRIMES] = {2,3,5};
int primesFound = 3;
int main(){
int numbersInDiagonal = 1;
int primesInDiagonal = 0;
int level;
generatePrimes();
for (level = 2 ; numbersInDiagonal/10 <= primesInDiagonal ; level++){
primesInDiagonal += primesOnThisLevel(level);
numbersInDiagonal += 4;
}
print(numbersInDiagonal)
print(primesInDiagonal)
int sideLenght = (2*level)-1;
print(sideLenght*sideLenght);
print(sideLenght);
return 0;
}
int primesOnThisLevel(int level){
int primesCount = 0;
int sideLenght = (2*level)-1;
int differenceBetweenCorners = 2*(level-1);
int cornerValue = sideLenght*sideLenght;
for (int i = 0 ; i < 3 ; i++){
cornerValue -= differenceBetweenCorners;
primesCount += isPrime(cornerValue);
}
return primesCount;
}
void generatePrimes(){
for (int i = 7 ; primesFound < NUM_OF_PRIMES ; i +=2 ){
if ( isPrime(i) ){
primes[primesFound++] = i;
}
}
print(primes[primesFound-1]);
}
int isPrime(int prospect){
if ( prospect == 3 || prospect == 5 ) return 1;
if ( !canBeExpressedAsPrime(prospect) ) return 0;
for (int i = 0 ; primes[i]*primes[i] <= prospect ; i++)
if ( prospect%primes[i] == 0 ) return 0;
return 1;
}
int canBeExpressedAsPrime(int prospect){
if ( prospect%6 == 1 ) return 1;
if ( prospect%6 == 5 ) return 1;
return 0;
}

Special Thanks to Roberto Trani whom pointed out the error which was regarding boundaries, the previous limit included 10% which was not supposed to happen, here it is the ammended main function, which is the perfect situation to use a do-while loop.
int main(){
int numbersInDiagonal = 1;
int primesInDiagonal = 0;
int level = 2;
generatePrimes();
do {
primesInDiagonal += primesOnThisLevel(level);
numbersInDiagonal += 4;
level++;
} while ( numbersInDiagonal < primesInDiagonal*10 );
int sideLenght = (2*(--level))-1;
print(sideLenght);
return 0;
}

Related

Calculate maximum path cost for a matrix in C

I am learning c and encountered maximum cost path question in which
Rules:
matrix is n x n size
Starting from the cell (bottommost leftmost cell), you want to go to the topmost
rightmost cell in a sequence of steps. In each step, you can go either right or up from
your current location.
I tried to solve using dynamic programming and this is the function I have written
computecost(int *utr,int n)//utr is the input matrix
{
int *str;
int i,j;
str=(int *)malloc(n*n*sizeof(int));
for(j=0;j<n;j++)//intialization of bottom row
{
str[n*(n-1)+j]=utr[n*(n-1)+j];
}
for(i=n-2;i>=0;i--)
{
for(j=0;j<n;j++)
{
str[n*i+j]=utr[n*i+j]+max(str[n*(i+1)+j],str[n*(i+1)+(j+1)]);
}
}
printf("%d",str[n*0+0]);
return 0;
}
and this is the input
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
scanf("%d",&str[n*i+j]);
}
}
but
for the matrix 5 x5
1 4 8 2 9
32 67 18 42 1
4 86 12 7 1
8 4 12 17 44
1 43 11 45 2
the desired output is 272 but I am getting 211.
the output matrix for my case
1 43 11 45 2
51 47 57 62 46
55 143 74 69 47
175 210 92 111 52
211 214 119 113 64
Can anyone help me?
You don't need dynamic programming for this since there are no overlapping sub-problems. Just use a simple recursion.
const int n = 5;
int mat[n][n] = {
{1,4,8,2,9},
{32,67,18,42,1},
{4,86,12,7,1},
{8,4,12,17,44},
{1,43,11,45,2}
}; // input matrix
int f(int x, int y, int sum){
if(x == 0 && y == 4)
return sum;
int p = 0, q = 0;
if(x - 1 >= 0)
p = f(x-1, y, sum + mat[x-1][y]);
if(y + 1 <= 4)
q = f(x, y+1, sum+mat[x][y+1]);
return max(p,q);
}
int main(){
int maxSum = f(4,0, mat[4][0]);
printf("%d\n", maxSum);
}
You were not very far to succeed.
In practice, you did not initialize correctly the bottom row.
Moreover, there was a little mistake in the iteration calculation.
This is the corrected code.
As said in a comment, it could be further simplified, by avoiding the use of a new array, simply updating the input array.
#include <stdio.h>
#include <stdlib.h>
int max (int a, int b) {
return (a > b) ? a : b;
}
int computecost(int *utr,int n) { //utr is the input matrix
int *str;
str = malloc (n*n*sizeof(int));
str[n*n - 1] = utr[n*n - 1];
for (int j = n-2; j >= 0; j--) { //intialization of bottom row {
str[n*(n-1)+j] = utr[n*(n-1)+j] + str[n*(n-1)+j+1]; // corrected
}
for (int i=n-2; i>=0; i--) {
str[n*i+n-1] = utr[n*i+n-1] + str[n*(i+1)+n-1];
for(int j = n-2; j >= 0; j--) {
str[n*i+j] = utr[n*i+j] + max(str[n*(i+1)+j],str[n*i + j+1]); // corrected
}
}
int cost = str[0];
free (str);
return cost;
}
int main() {
int A[25] = {
1,43,11,45,2,
8,4,12,17,44,
4,86,12,7,1,
32,67,18,42,1,
1,4,8,2,9
};
int ans = computecost (A, 5);
printf ("%d\n", ans);
return 0;
}

Eratosthenes prime numbers

I have created a program to search for prime numbers. It works without problems until the entered number is smaller than 52, when it is bigger output prints out some blank (0) numbers and I don't know why. Also other numbers have blank output.
My code is:
#include <stdio.h> //Prime numbers
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <unistd.h>
int c[100], n, a[50], d, e, b = 1;
void sort() {
for (int i = 1; i < n; i++) {
if (c[i] > 1) {
a[b] = c[i];
printf("%d %d %d\n", a[1], b, i);
b++;
e = 2;
d = 0;
while (d <= n) {
d = c[i] * e;
c[d - 1] = 0;
e++;
}
}
}
}
int main() {
printf("Enter number as an limit:\n");
scanf("%d", &n);
for (int i = 0; i < n; i++) {
c[i] = i + 1;
}
sort();
printf("Prime numbers between 1 and %d are:\n", n);
for (int i = 1; i < b; i++) {
printf("%d ", a[i]);
}
return 0;
}
Here is output for 25:
Enter number as an limit:
25
2 1 1
2 2 2
2 3 4
2 4 6
2 5 10
2 6 12
2 7 16
2 8 18
2 9 22
Prime numbers between 1 and 25 are:
2 3 5 7 11 13 17 19 23
But for 83 is:
Enter number as an limit:
83
2 1 1
2 2 2
2 3 4
2 4 6
2 5 10
2 6 12
2 7 16
2 8 18
2 9 22
2 10 28
2 11 30
2 12 36
2 13 40
2 14 42
2 15 46
2 16 52
0 17 58
0 18 60
0 19 66
0 20 70
0 21 72
0 22 78
0 23 82
Prime numbers between 1 and 83 are:
0 3 5 7 11 0 17 19 23 29 31 37 0 43 47 53 0 61 67 71 73 79 83
Blank spots always spots after 17th prime number. And always the blank numbers are the same. Can you help me please what is the problem?
The loop setting entries in c for multiples of c[i] runs too far: you should compute the next d before comparing against n:
for (d = c[i] * 2; d <= n; d += c[i]) {
c[d - 1] = 0;
}
As a matter of fact you could start at d = c[i] * c[i] because all lower multiples have already been seen during the previous iterations of the outer loop.
Also note that it is confusing to store i + 1 into c[i]: the code would be simpler with an array of booleans holding 1 for prime numbers and 0 for composite.
Here is a modified version:
#include <stdio.h>
int main() {
unsigned char c[101];
int a[50];
int n, b = 0;
printf("Enter number as a limit:\n");
if (scanf("%d", &n) != 1 || n < 0 || n > 100) {
printf("invalid input\n");
return 1;
}
for (int i = 0; i < n; i++) {
c[i] = 1;
}
for (int i = 2; i < n; i++) {
if (c[i] != 0) {
a[b] = i;
//printf("%d %d %d\n", a[0], b, i);
b++;
for (int d = i * i; d <= n; d += i) {
c[d] = 0;
}
}
}
printf("Prime numbers between 1 and %d are:\n", n);
for (int i = 0; i < b; i++) {
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
Output:
chqrlie$ ./sieve4780
Enter number as a limit:
25
Prime numbers between 1 and 25 are:
2 3 5 7 11 13 17 19 23
chqrlie$ ./sieve4780
Enter number as a limit:
83
Prime numbers between 1 and 83 are:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79
Your problem seems to be caused by the fact that you have declared an array with size 50, but in fact it goes further than that: imagine you want to use Eratosthenes' procedure to find the first 10,000 prime numbers. Does this mean that you need to declare an array of size 10,000 first (or even bigger), risking to blow up your memory?
No: best thing to do is to work with collections where you don't need to set the maximum size at declaration time, like a linked list, a vector, ..., like that you can make your list grow as much as you like during runtime.

Sorting sides of n triangles according to the area

Given n triangles, with sides a,b,c print them in the same style by sorting them from the smallest to the largest.
Complete problem: https://www.hackerrank.com/challenges/small-triangles-large-triangles/problem
In the solution, we have a structure named as Triangle. It has 3 integers a,b,c. An array of Triangle is made, named as tr and the input is passed to the function sort_by_area.
My approach is to apply bubble sort on this array.But instead of comparing tr[j] > tr[j+1] like we do in normal bubble sort, I'm comparing the areas of tr[j] and tr[j+1]. Now, if area of tr[j] > tr[j+1]: Swap.
The problem: In the end the results are wrong. The array doesn't sort properly. First I thought it's a typo somewhere so I rewrite the code but the problem persists.
double area (int a, int b, int c)
{
double p = (a+b+c)/2;
return sqrt(p*(p-a)*(p-b)*(p-c));
}
void sort_by_area(triangle* tr, int n) {
/**
* Sort an array a of the length n
*/
int i,j;
double area1, area2;
triangle temp;
for(i = 0; i < n-1;++i)
{
for(j = 0; j < n-i-1; ++j)
{
area1 = area(tr[j].a , tr[j].b, tr[j].c);
area2 = area(tr[j+1].a , tr[j+1].b, tr[j+1].c);
if(area1 > area2)
{
temp = tr[j];
tr[j] = tr[j+1];
tr[j+1] = temp;
}
}
}
}
input: 20
23 37 47
22 18 5
58 31 31
28 36 40
54 62 11
31 41 14
53 18 54
41 38 55
55 44 44
44 48 18
26 41 65
20 23 21
58 61 50
28 56 56
20 39 32
33 45 49
26 41 62
31 46 39
48 49 67
57 33 45
expected output:
22 18 5
31 41 14
20 23 21
54 62 11
26 41 65
58 31 31
20 39 32
26 41 62
44 48 18
23 37 47
53 18 54
28 36 40
31 46 39
33 45 49
57 33 45
28 56 56
41 38 55
55 44 44
48 49 67
58 61 50
actual output:
22 18 5
54 62 11
31 41 14
20 23 21
26 41 65
20 39 32
58 31 31
26 41 62
23 37 47
44 48 18
53 18 54
28 36 40
31 46 39
33 45 49
57 33 45
28 56 56
41 38 55
55 44 44
48 49 67
58 61 50
This is my solution for this challenge:
double area(triangle t){
double p = (t.a+t.b+t.c)/2.0;
return sqrt(p*(p-t.a)*(p-t.b)*(p-t.c));
}
void sort_by_area(triangle* tr, int n) {
int i,j;
for(i=0;i<n-1;i++){
for(j=i+1;j<n;j++){
if(area(tr[j]) < area(tr[i])){
triangle temp = tr[i];
tr[i]=tr[j];
tr[j]=temp;
}
}
}
}
Your usage of the 'for' loop for comparing triangles is this (by triangle, I mean triangle's area):
for(i = 0; i < n - 1; ++i){
...
...
for(j = 0; j < n - i - 1; ++j){
...
}
}
Observe carefully: The loop you used fails to compare the last elements of the arrays.
I just improvised your code and it works:
#include < stdio.h >
#include < stdlib.h >
#include < math.h >
struct triangle
{
int a;
int b;
int c;
};
typedef struct triangle triangle;
float area(int a, int b, int c)
{
float p;
p = (float)(a + b + c) / 2;
return sqrt(p * (p - a) * (p - b) * (p - c));
}
void sort_by_area(triangle* tr, int n)
{
int i, j;
float area1, area2;
triangle temp[5];
for (i = 0; i < n - 1; i++)
{
for (j = 0; j < n - i - 1; j++)
{
area1 = area(tr[j].a, tr[j].b, tr[j].c);
area2 = area(tr[j + 1].a, tr[j + 1].b, tr[j + 1].c);
if (area1 > area2)
{
temp[0] = tr[j];
tr[j] = tr[j + 1];
tr[j + 1] = temp[0];
}
}
}
}
int main()
{
int n;
scanf("%d", &n);
triangle* tr = malloc(n * sizeof(triangle));
for (int i = 0; i < n; i++)
{
scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c);
}
sort_by_area(tr, n);
for (int i = 0; i < n; i++)
{
printf("%d %d %d\n", tr[i].a, tr[i].b, tr[i].c);
}
return 0;
}
An edit of #Zümrüd-ü Anka's answer to match the bubble sorts you'll find elsewhere. Your loops actually should work fine, both for loops here are the same as yours. This passes the test cases for HackerRank. I think it was actually just the integer division that was giving you an issue.
double area(triangle t){
double p = (t.a+t.b+t.c)/2.0;
return sqrt(p*(p-t.a)*(p-t.b)*(p-t.c));
}
void sort_by_area(triangle* tr, int n) {
int i,j;
for(i=0;i<n-1;i++){
for(j=0;j<n-i-1;j++){
if(area(tr[j]) > area(tr[j+1])){
triangle temp = tr[j+1];
tr[j+1]=tr[j];
tr[j]=temp;
}
}
}
}

Delete any number of Columns in 2D dynamic array and resize the matrix size after column deletion

I am trying to delete first 20 columns from each of the slices of my 3D dynamic array. I guessed trying to write a function for 2D dynamic array would solve the problem which I would iterate over each of the levels of 3D array. I got an example in stackoverflow which I am trying to make work.
But the problem is the function can not delete the whole column. Instead it only delete one element. Can anyone give me idea how to delete whole column from a 2D dynamic array?
void removeColumn(int** matrix, int col){
MATRIX_WIDTH--;
for(int i=0;i<MATRIX_HEIGHT; i++) {
while(col<MATRIX_WIDTH)
{
//move data to the left
matrix[i][col]=matrix[i][col+1];
col++;
} matrix[i] = realloc(matrix[i], sizeof(double)*MATRIX_WIDHT); }
My expected ouput is like
Sample input:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
sample output:
1 3 4
5 7 8
9 11 12
13 15 16
Update: here is the code which delete the column completely after using #frslm advice
but matrix is not resizing.
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
int** fill(size_t rows, size_t cols, int input[][cols])
{
int i,j,count=1;
int** result;
result = malloc((rows)*sizeof(int*));
for(i=0;i<rows;i++)
{
result[i]=malloc(cols*sizeof(int));
for(j=0;j<cols;j++)
{
result[i][j]=count++;
}
}
return result;
}
void printArray2D(size_t rows, size_t cols,int** input)
{
int i,j;
for(i=0;i<rows;i++)
{
for(j=0;j<cols;j++)
{
printf(" %4d",input[i][j]);
}
printf("\n");
}
}
void removeColumn(int** matrix, int col2del , int rows, int cols){
int MATRIX_WIDTH = cols;
int MATRIX_HEIGHT = rows;
MATRIX_WIDTH--;
for(int i=0;i<MATRIX_HEIGHT; i++) {
int curr_col = col2del;
while(curr_col<MATRIX_WIDTH)
{
//move data to the left
matrix[i][curr_col]=matrix[i][curr_col+1];
curr_col++;
}
//matrix[i] = realloc(matrix[i], sizeof(int)*MATRIX_WIDTH); // <- int, not double
matrix[i] = realloc(matrix[i], sizeof (matrix[i][0])*MATRIX_WIDTH);
}
}
int main()
{
int arRow,arCol;
arRow =8;
arCol = 9;
int ar[arRow][arCol];
int **filled;
filled = fill(arRow, arCol, ar);
printArray2D(arRow,arCol,filled);
removeColumn(filled, 3,arRow,arCol);
printf("After 3rd Column Delete.......\n");
printArray2D(arRow,arCol,filled);
return(0);
}
Output: last column duplicates
1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18
19 20 21 22 23 24 25 26 27
28 29 30 31 32 33 34 35 36
37 38 39 40 41 42 43 44 45
46 47 48 49 50 51 52 53 54
55 56 57 58 59 60 61 62 63
64 65 66 67 68 69 70 71 72
After 3rd Column Delete.......
1 2 3 5 6 7 8 9 9
10 11 12 14 15 16 17 18 18
19 20 21 23 24 25 26 27 27
28 29 30 32 33 34 35 36 36
37 38 39 41 42 43 44 45 45
46 47 48 50 51 52 53 54 54
55 56 57 59 60 61 62 63 63
64 65 66 68 69 70 71 72 72
You increment col until it reaches the end of the first row, but you never reset it for subsequent rows, which is why you end up removing only the first row's column.
Make sure you reset col at the start of each iteration:
void removeColumn(int** matrix, int col){
MATRIX_WIDTH--;
for(int i=0;i<MATRIX_HEIGHT; i++) {
int curr_col = col; // <- use a temporary `col` variable for each row
while(curr_col<MATRIX_WIDTH)
{
//move data to the left
matrix[i][curr_col]=matrix[i][curr_col+1];
curr_col++;
}
matrix[i] = realloc(matrix[i], sizeof(int)*MATRIX_WIDTH); // <- int, not double
}
}
Edit (in response to OP's edit):
Ensure that removeColumn() updates the number of columns (cols) after resizing the matrix; one way to do that is by using a pointer: int *cols as a parameter instead of int cols (don't forget to pass in an address, &arCol, when calling this function). Also, I suggest getting rid of the unnecessary MATRIX_HEIGHT variable:
void removeColumn(int** matrix, int col2del, int rows, int *cols){
int MATRIX_WIDTH = --(*cols);
for(int i=0;i<rows; i++) {
int curr_col = col2del;
while(curr_col<MATRIX_WIDTH)
{
//move data to the left
matrix[i][curr_col]=matrix[i][curr_col+1];
curr_col++;
}
matrix[i] = realloc(matrix[i], sizeof(matrix[i][0])*MATRIX_WIDTH);
}
}
It's easier if you pass the width and height, and update the width:
void removeColumn(int** matrix, int col, int* width, int height)
{
int j, i;
for (j = 0; j < height; ++j) {
if (col == *width-1) {
continue;
}
for (i = col; i < *width; ++i) {
matrix[j][i] = matrix[j][i+1];
}
// this is not necessary, but I'm adding as requested
matrix[j] = realloc(
matrix[j],
sizeof(int) * (*width - 1)
);
}
--(*width);
}
You could also avoid dynamic memory allocations, avoiding memory defragmentation:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int max_width, max_height;
int width, height;
int* values;
} matrix;
void removeColumn(matrix* matrix, int col)
{
int y, i;
for (y = 0; y < matrix->height; ++y) {
if (col == matrix->width-1) {
continue;
}
i = col + matrix->height * y;
while (i < matrix->width) {
matrix->values[i] = matrix->values[++i];
}
}
--matrix->width;
}
void printMatrix(matrix* matrix)
{
int y, x;
for (y = 0; y < matrix->height; ++y) {
for (x = 0; x < matrix->width; ++x) {
printf("%d ", matrix->values[x + matrix->width * y]);
}
printf("\n");
}
}
int main ()
{
int y, x = 0;
matrix matrix;
matrix.max_width = 4;
matrix.max_height = 4;
matrix.width = 4;
matrix.height = 4;
int values[4][4];
matrix.values = &values;
for (y = 0; y < matrix.height; ++y) {
for (x = 0; x < matrix.width; ++x) {
int i = x + matrix.width * y;
matrix.values[i] = i % 10;
}
}
printMatrix(&matrix);
removeColumn(&matrix, 1);
printf("===\n");
printMatrix(&matrix);
}
Tested using: https://www.tutorialspoint.com/compile_c_online.php
ADDED
But when the array size is too big then do we have any other option
but using dynamic array
If you want to make a resizable array, you could use a single malloc when allocating the array and use a realloc when the width will be greater than max_width or the height will be greater than max_height.
Nevertheless, I believe we should try to avoid lots of dynamic allocations using malloc or realloc, because they're slow (though most of the time you won't notice), they can severely defragment memory and the way you did it generates lots of unnecessary cache misses.
You should also grow them more than required, for instance, exponentially, if you don't know that you will need to resize the array several times. That's how hashes and dynamic arrays are usually implemented (properly).
You may find, for instance, several JSON, XML and HTML C libraries without dynamic memory to avoid its pitfalls, and in many professional video games, a huge malloc might be used to avoid lots of them and simple arrays are used liberally.
Why is realloc eating tons of memory?
https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
http://gameprogrammingpatterns.com/data-locality.html
https://codefreakr.com/how-is-c-stl-implemented-internally/
http://gamesfromwithin.com/start-pre-allocating-and-stop-worrying
CppCon 2014: Mike Acton "Data-Oriented Design and C++"
Of course, you can use dynamic memory, but it's better to understand its pitfalls for better decisions.

Sorting 2d array (matrix) in C

I have a task to sort a 2d array but it is really hard for me. I can't figure out where I'm making a mistake.
It will be good to use while loop instead of for loop
Here is the task:
Enter a square matrix of dimensions n.
Elements below main diagonal sort in ascending order.
Elements above main diagonal sort in descending order.
Elements on main diagonal sort:
first even numbers in ascending order.
then odd numbers in descending order.
Matrix before sorting:
1 5 4 7 2
4 8 5 9 0
2 7 6 5 3
3 1 7 4 9
2 5 1 7 3
Matrix after sorting :
4 9 9 7 5
1 6 5 5 4
1 2 8 3 2
2 3 4 3 0
5 7 7 7 1
Here is the code:
#include <stdio.h>
#include <stdlib.h>
int main () {
int n, i, j, a, k, l, o;
int m[50][50];
printf ("Enter n of square matrix : \n");
scanf ("%d", &n);
printf ("Enter rows and columns numbers n :\n");
i = 0;
while (i < n) {
j = 0;
while (j < n) {
scanf ("%d", &m[i][j]);
j++;
}
i++;
}
printf ("Matrix before sorting \n");
i = 0;
while (i < n) {
j = 0;
while (j < n) {
printf ("%d ", m[i][j]);
j++;
}
printf ("\n");
i++;
}
printf ("Matrix after sorting \n");
i = 0;
while (i < n) {
j = 0;
while (j < n) {
if (i < j) {
k = j + 1;
while (k < (n - 1)) {
if (m[i][k] < m[i][k + 1]) {
a = m[i][k];
m[i][k] = m[i][k + 1];
m[i][k + 1] = a;
}
k++;
}
}
else if (i > j) {
l = i + 1;
while (l < (n - 1)) {
if (m[l][j] > m[l + 1][j]) {
a = m[l][j];
m[l][j] = m[l + 1][j];
m[l + 1][j] = a;
}
l++;
}
}
else {
if (m[i][j] % 2 == 0 && m[i + 1][j + 1] % 2 == 0) {
if (m[i][j] > m[i + 1][j + 1]) {
a = m[i][j];
m[i][j] = m[i + 1][j + 1];
m[i + 1][j + 1] = a;
}
}
if (m[i][j] % 2 != 0 && m[i + 1][j + 1] % 2 != 0) {
if (m[i][j] < m[i + 1][j + 1]) {
a = m[i][j];
m[i][j] = m[i + 1][j + 1];
m[i + 1][j + 1] = a;
}
}
}
j++;
}
i++;
}
i = 0;
while (i < n) {
j = 0;
while (j < n) {
printf ("%d ", m[i][j]);
j++;
}
printf ("\n");
i++;
}
return 0;
}
CHANGES MADE ON 02/02/2018
I need to make simple code , without things like size_t,buffer and pointers etc...
I made some code but when i use odd n number of matrix it wont work properly (for example 5x5) I don't know where i m making mistake .
#include <stdio.h>
#include <stdlib.h>
int main()
{
static int a[500][500];
int i,j,l,k,m,b,n,t,d,c;
printf("Unesite n kvadratne matrice : \n");
scanf("%d" , &n);
printf("Matrica pre sortiranja \n \n");
for ( i = 0; i < n; i++)
{
for ( j = 0; j < n ; j++)
{
scanf("%d",&a[ i ][ j ]);
}
}
for ( i = 0; i < n; i++)
{
for ( j = 0; j < n; j++)
{
if ( i > j ) // ispod dijagonale
{
for ( l = i ; l < n ; l++)
{
for ( k = j ; k < l ; k++ )
{
if ( a[ i ][ j ] > a[ l ][ k ] && k < l )
{
t = a[ i ][ j ];
a[ i ][ j ] = a[ l ][ k ];
a[ l ][ k ] = t ;
}
}
}
}
if ( i < j ) // iznad dijagonale
{
for ( m = i ; m < n ; m++)
{
for ( b = j ; b < n ; b++)
{
if ( a[ i ][ j ] < a[ m ][ b ] && m < b )
{
t = a[ i ][ j ];
a[ i ][ j ] = a[ m ][ b ];
a[ m ][ b ] = t ;
}
}
}
}
if ( i == j ) // dijagonala
{
for (d = i ; d < n ; d++)
{
for ( c = d + 1 ; c < n ; c++)
{
if ( a[ d ] [ d ] % 2 != 0 && a[ c ] [ c]%2 == 0 )
{
t = a[ d ] [ d ] ;
a[ d ] [ d ] = a[ c ] [ c] ;
a[ c ] [ c] = t ;
}
}
}
for (d = i ; d < n ; d++)
{
for ( c = d + 1 ; c < n ; c++)
{
if ( a[ d ][ d ] %2 == 0 && a[ c ][ c ] %2 ==0
&& a[ d ][ d ] > a [ c ][ c ])
{
t = a[ d ] [ d ] ;
a[ d ] [ d ] = a[ c ] [ c] ;
a[ c ] [ c] = t ;
}
else if ( a[ d ][ d ] %2 != 0 && a[ c ][ c ] %2
!=0 && a[ d ][ d ] < a [ c ][ c ])
{
t = a[ d ] [ d ] ;
a[ d ] [ d ] = a[ c ] [ c] ;
a[ c ] [ c] = t ;
}
}
}
}
}
}
printf("Posle sortiranja : \n");
for ( i = 0; i < n; i++)
{
for ( j = 0; j < n;j++)
{
printf(" %d ",a[i][j]);
}
printf("\n \n");
}
return 0;
}
It's an intriguing problem. As I outlined in a comment, I think the solution has to be tackled in three separate sorting operations:
Sorting the diagonal
Sorting the upper triangle
Sorting the lower triangle
The sequence in which those operations occur is immaterial. Indeed, if you want to run the three sorts in parallel with threads, you could do that.
The trick to sorting the diagonal is to write a comparison function that ensures that all even numbers come before all odd numbers (so every even number is deemed smaller than any odd number), but when two even numbers are compared, they're sorted in ascending order whereas when two odd numbers are compared, they're sorted in descending order. The cmp_aeod() function (ascending even odd descending) function achieves this.
It would be possible to work with just one of the cmp_asc() and cmp_dsc() functions, but it is more straight-forward to have both. The (x > y) - (x < y) idiom does two comparison always, but if x is bigger than y, the first term is 1, the second 0, and the result is 1. If x is smaller than y, the first term is 0, the second is 1, and the result is -1. If x is equal to y, of course, both terms are 0 and the result is also 0.
The key to sorting the triangles is to note that sorting algorithms work on contiguous arrays, but the data in the triangles is not contiguous. The solution shown is to number the elements in the triangle from 0 to m, where m = (n * (n - 1)) / 2, given that the square matrix is an n by n one. The code then needs to be able to identify which indexes in the matrix should be accessed for the corresponding element number, and this mapping is done by the ut or lt matrix in the triangle-sorting functions. I couldn't work out a non-iterative formula to convert the sequence number in the triangle into a row/col pair, so I created the map matrix. This gives an auxilliary storage requirement of size O(N2).
The sort algorithm used is a simple quadratic sort; you can change it for a more sophisticated algorithm (quicksort or whatever) as you wish.
/*
** + Enter a square matrix of dimensions n .
** + Elements below main diagonal sort in ascending order.
** + Elements above main diagonal sort in descending order.
** + Elements on main diagonal sort :
** - first even numbers in ascending order.
** - then odd numbers in descending order.
*/
static inline int cmp_asc(int x, int y) { return (x > y) - (x < y); }
static inline int cmp_dsc(int x, int y) { return (x < y) - (x > y); }
static inline int cmp_eaod(int x, int y)
{
int px = x & 1;
int py = y & 1;
if (px != py)
return px - py;
if (px == 1)
return cmp_dsc(x, y);
return cmp_asc(x, y);
}
#include <stdio.h>
static void print_matrix(const char *tag, size_t r, size_t c, int matrix[r][c])
{
printf("%s:\n", tag);
for (size_t i = 0; i < r; i++)
{
for (size_t j = 0; j < c; j++)
printf("%3d", matrix[i][j]);
putchar('\n');
}
}
static void sort_diagonal(size_t n, int matrix[n][n])
{
for (size_t i = 0; i < n; i++)
{
for (size_t j = i + 1; j < n; j++)
{
if (cmp_eaod(matrix[i][i], matrix[j][j]) > 0)
{
int t = matrix[i][i];
matrix[i][i] = matrix[j][j];
matrix[j][j] = t;
}
}
}
}
/*
** D0 U0 U1 U2 U3
** L0 D1 U4 U5 U6
** L1 L2 D3 U7 U8
** L3 L4 L5 D4 U9
** L6 L7 L8 L9 D5
**
** D0 = (0, 0); U0 = (0, 1); U1 = (0, 2); U2 = (0, 3); U3 = (0, 4);
** L0 = (1, 0); D1 = (1, 1); U4 = (1, 2); U5 = (1, 3); U6 = (1, 4);
** L1 = (2, 0); L2 = (2, 1); D2 = (2, 2); U7 = (2, 3); U8 = (2, 4);
** L3 = (3, 0); L4 = (3, 1); L5 = (3, 2); D3 = (3, 3); U9 = (3, 4);
** L6 = (4, 0); L7 = (4, 1); L8 = (4, 2); L9 = (4, 3); D4 = (4, 4);
*/
/*
** It is probably best to create an array that does the mapping from an
** index to the row/column, with one such mapping for the lower
** triangle; one for the upper triangle.
*/
static void sort_lt(size_t n, int matrix[n][n])
{
size_t m = (n * (n - 1)) / 2;
int lt[m][2];
size_t r = 1;
size_t c = 0;
for (size_t i = 0; i < m; i++)
{
lt[i][0] = r;
lt[i][1] = c++;
if (c == r)
{
r++;
c = 0;
}
}
//print_matrix("LT map", m, 2, lt);
for (size_t i = 0; i < m; i++)
{
size_t xi = lt[i][0];
size_t yi = lt[i][1];
for (size_t j = i + 1; j < m; j++)
{
size_t xj = lt[j][0];
size_t yj = lt[j][1];
if (cmp_asc(matrix[xi][yi], matrix[xj][yj]) > 0)
{
int t = matrix[xi][yi];
matrix[xi][yi] = matrix[xj][yj];
matrix[xj][yj] = t;
}
}
}
}
static void sort_ut(size_t n, int matrix[n][n])
{
size_t m = (n * (n - 1)) / 2;
int ut[m][2];
size_t r = 0;
size_t c = 0;
for (size_t i = 0; i < m; i++)
{
ut[i][0] = r;
ut[i][1] = ++c;
if (c == n - 1)
{
r++;
c = r;
}
}
//print_matrix("UT map", m, 2, ut);
for (size_t i = 0; i < m; i++)
{
size_t xi = ut[i][0];
size_t yi = ut[i][1];
for (size_t j = i + 1; j < m; j++)
{
size_t xj = ut[j][0];
size_t yj = ut[j][1];
if (cmp_dsc(matrix[xi][yi], matrix[xj][yj]) > 0)
{
int t = matrix[xi][yi];
matrix[xi][yi] = matrix[xj][yj];
matrix[xj][yj] = t;
}
}
}
}
static void test_matrix(const char *tag, size_t n, int matrix[n][n])
{
char buffer[64];
snprintf(buffer, sizeof(buffer), "Matrix %s (%zux%zu) - before", tag, n, n);
print_matrix(buffer, n, n, matrix);
//print_matrix("Before sorting diagonal", n, n, matrix);
sort_diagonal(n, matrix);
//print_matrix("After sorting diagonal", n, n, matrix);
sort_lt(n, matrix);
//print_matrix("After sorting lower triangle", n, n, matrix);
sort_ut(n, matrix);
//print_matrix("After sorting upper triangle", n, n, matrix);
snprintf(buffer, sizeof(buffer), "Matrix %s (%zux%zu) - after", tag, n, n);
print_matrix(buffer, n, n, matrix);
}
int main(void)
{
int matrix1[5][5] =
{
{ 1, 5, 4, 7, 2 },
{ 4, 8, 5, 9, 0 },
{ 2, 7, 6, 5, 3 },
{ 3, 1, 7, 4, 9 },
{ 2, 5, 1, 7, 3 },
};
test_matrix("SAMPLE1", 5, matrix1);
// gen_matrix -i -n matrix2 -r 10 -c 10 -L 10 -H 99
int matrix2[10][10] =
{
{ 87, 32, 98, 58, 60, 71, 46, 81, 70, 14, },
{ 22, 92, 15, 98, 51, 26, 94, 67, 46, 56, },
{ 71, 89, 86, 16, 20, 89, 97, 89, 45, 92, },
{ 63, 13, 76, 19, 75, 19, 66, 89, 58, 41, },
{ 82, 68, 75, 26, 58, 20, 89, 87, 65, 66, },
{ 74, 83, 68, 92, 10, 98, 90, 21, 39, 63, },
{ 24, 65, 23, 68, 62, 44, 48, 22, 27, 59, },
{ 26, 27, 71, 71, 51, 31, 43, 69, 92, 10, },
{ 54, 19, 41, 50, 10, 89, 42, 52, 94, 54, },
{ 42, 50, 79, 48, 77, 18, 29, 40, 61, 63, },
};
test_matrix("SAMPLE 2", 10, matrix2);
return 0;
}
When run, the output is:
Matrix SAMPLE1 (5x5) - before:
1 5 4 7 2
4 8 5 9 0
2 7 6 5 3
3 1 7 4 9
2 5 1 7 3
Matrix SAMPLE1 (5x5) - after:
4 9 9 7 5
1 6 5 5 4
1 2 8 3 2
2 3 4 3 0
5 7 7 7 1
Matrix SAMPLE 2 (10x10) - before:
87 32 98 58 60 71 46 81 70 14
22 92 15 98 51 26 94 67 46 56
71 89 86 16 20 89 97 89 45 92
63 13 76 19 75 19 66 89 58 41
82 68 75 26 58 20 89 87 65 66
74 83 68 92 10 98 90 21 39 63
24 65 23 68 62 44 48 22 27 59
26 27 71 71 51 31 43 69 92 10
54 19 41 50 10 89 42 52 94 54
42 50 79 48 77 18 29 40 61 63
Matrix SAMPLE 2 (10x10) - after:
48 98 98 97 94 92 92 90 89 89
10 58 89 89 87 81 75 71 70 67
10 13 86 66 66 65 63 60 59 58
18 19 22 92 58 56 54 51 46 46
23 24 26 26 94 45 41 39 32 27
27 29 31 40 41 98 26 22 21 20
42 42 43 44 48 50 87 20 19 16
50 51 52 54 61 62 63 69 15 14
65 68 68 68 71 71 71 74 63 10
75 76 77 79 82 83 89 89 92 19
The 'SAMPLE1 - before' data corresponds to the input in the question, and the 'SAMPLE 1 - after' output corresponds to the desired output. The bigger matrix result seems to match the requirements too.
I developed the diagonal sort first because it is by far the easiest; the even ascending, odd descending order is a problem I'd solved before. I then developed one of the triangle sorts, and debugged that. Getting the second triangle sorted was then very straight-forward. Making sure that I had a good flexible matrix printing function also helped. The commented out calls were all used at some point during the development.
Timing tests
The 'sort in place' code shown becomes very slow as the matrix grows. There's an alternative method — copy the data out of the matrix into a 1D vector; sort the vector; copy the data back into the matrix. I did some timing tests. With a matrix size of 10x10, the times were comparable (15µs for the basic sort code shown above; 12µs for code using extract, quicksort, insert). When the matrix size was 20x20, the performance was firmly in favour of the extract, quicksort, insert: 172µs vs 32µs in favour of quicksort, and by 900x900, the basic sort was taking 285s vs 0.054s for quicksort. The discrepancy is growing faster than a quadratic sort can account for. The trouble is the very complex access path to get to the elements being sorted. The code for creating the lt and ut matrices remains useful. The lt and ut matrices tell you which cells to collect the data from for sorting the triangle (order doesn't much matter while extracting the data since it is about to be sorted anyway), but also (crucially) tells you where to place each element in the sorted data.
You can find my code on GitHub in my SOQ (Stack
Overflow Questions) repository in the
src/so-4829-1562
sub-directory. (Note that at the moment, the code uses VLAs for intermediate matrices; it crashes at around 1000x1000 on a Mac. I need to change it to use dynamic memory allocation in the sort code as well as in the data generation code. It may get fixed, sooner or later. Also, I'm not convinced there's enough time between refreshes of hardware to use the basic sort on 10000x10000 size matrices, though I think the quick sort code would still be usable.)
Another interesting test would be to adapt the 'basic sort' to use extract, quadratic sort, insert when sorting the triangles. I'm pretty sure it would vastly outpace the 'basic sort' code, though it would still lose out to the O(NlogN) quick sort code as the arrays got bigger. The copying time becomes negligible compared to the sorting time.
Using qsort() etc
/* SO 4829-1562 */
#include "time.sort2d-31.h"
#include "emalloc.h"
/*
** + Enter a square matrix of dimensions n .
** + Elements below main diagonal sort in ascending order.
** + Elements above main diagonal sort in descending order.
** + Elements on main diagonal sort :
** - first even numbers in ascending order.
** - then odd numbers in descending order.
*/
/* Variation 4: Use system qsort() and common code to coordinate sorting of triangles */
/* Avoids two matrices lt and ut, thereby reducing the extra data space needed. */
static inline int cmp_asc(int x, int y) { return (x > y) - (x < y); }
static inline int cmp_dsc(int x, int y) { return (x < y) - (x > y); }
static inline int cmp_eaod(int x, int y)
{
int px = x & 1;
int py = y & 1;
if (px != py)
return px - py;
if (px == 1)
return cmp_dsc(x, y);
return cmp_asc(x, y);
}
static int qs_cmp_int_asc(const void *v1, const void *v2)
{
int i1 = *(const int *)v1;
int i2 = *(const int *)v2;
return cmp_asc(i1, i2);
}
static int qs_cmp_int_dsc(const void *v1, const void *v2)
{
int i1 = *(const int *)v1;
int i2 = *(const int *)v2;
return cmp_dsc(i1, i2);
}
static int qs_cmp_int_eaod(const void *v1, const void *v2)
{
int i1 = *(const int *)v1;
int i2 = *(const int *)v2;
return cmp_eaod(i1, i2);
}
static void sort_diagonal(size_t n, int matrix[n][n])
{
int data[n];
for (size_t i = 0; i < n; i++)
data[i] = matrix[i][i];
qsort(data, n, sizeof(data[0]), qs_cmp_int_eaod);
for (size_t i = 0; i < n; i++)
matrix[i][i] = data[i];
}
/*
** D0 U0 U1 U2 U3
** L0 D1 U4 U5 U6
** L1 L2 D3 U7 U8
** L3 L4 L5 D4 U9
** L6 L7 L8 L9 D5
**
** D0 = (0, 0); U0 = (0, 1); U1 = (0, 2); U2 = (0, 3); U3 = (0, 4);
** L0 = (1, 0); D1 = (1, 1); U4 = (1, 2); U5 = (1, 3); U6 = (1, 4);
** L1 = (2, 0); L2 = (2, 1); D2 = (2, 2); U7 = (2, 3); U8 = (2, 4);
** L3 = (3, 0); L4 = (3, 1); L5 = (3, 2); D3 = (3, 3); U9 = (3, 4);
** L6 = (4, 0); L7 = (4, 1); L8 = (4, 2); L9 = (4, 3); D4 = (4, 4);
*/
typedef void (*Copier)(int *val1, int *val2);
static void copy_a_to_b(int *val1, int *val2) { *val2 = *val1; }
static void copy_b_to_a(int *val1, int *val2) { *val1 = *val2; }
static void copy_lt_data(size_t n, int matrix[n][n], int vector[], Copier copy)
{
size_t m = (n * (n - 1)) / 2;
size_t r = 1;
size_t c = 0;
for (size_t i = 0; i < m; i++)
{
(*copy)(&matrix[r][c++], &vector[i]);
if (c == r)
{
r++;
c = 0;
}
}
}
static void copy_ut_data(size_t n, int matrix[n][n], int vector[], Copier copy)
{
size_t m = (n * (n - 1)) / 2;
size_t r = 0;
size_t c = 0;
for (size_t i = 0; i < m; i++)
{
(*copy)(&matrix[r][++c], &vector[i]);
if (c == n - 1)
{
r++;
c = r;
}
}
}
typedef void (*Mapper)(size_t n, int matrix[n][n], int vector[], Copier copy);
typedef int (*Comparator)(const void *v1, const void *v2);
static void sort_triangle(size_t n, int matrix[n][n], Mapper mapper, Comparator cmp)
{
size_t m = (n * (n - 1)) / 2;
int *data = MALLOC(m * sizeof(*data));
(*mapper)(n, matrix, data, copy_a_to_b);
qsort(data, m, sizeof(data[0]), cmp);
(*mapper)(n, matrix, data, copy_b_to_a);
FREE(data);
}
void quick_sort(size_t n, int matrix[n][n])
{
sort_diagonal(n, matrix);
sort_triangle(n, matrix, copy_lt_data, qs_cmp_int_asc);
sort_triangle(n, matrix, copy_ut_data, qs_cmp_int_dsc);
}
I also put a timing test together — see GitHub for the source code. The results were:
Basic sort (10x10) - elapsed: 0.000010
Clean sort (10x10) - elapsed: 0.000008
Quick sort (10x10) - elapsed: 0.000015
Basic sort (20x20) - elapsed: 0.000153
Clean sort (20x20) - elapsed: 0.000112
Quick sort (20x20) - elapsed: 0.000026
Basic sort (30x30) - elapsed: 0.000800
Clean sort (30x30) - elapsed: 0.000645
Quick sort (30x30) - elapsed: 0.000060
Basic sort (40x40) - elapsed: 0.002661
Clean sort (40x40) - elapsed: 0.002057
Quick sort (40x40) - elapsed: 0.000106
Basic sort (50x50) - elapsed: 0.006347
Clean sort (50x50) - elapsed: 0.005038
Quick sort (50x50) - elapsed: 0.000175
Basic sort (60x60) - elapsed: 0.014120
Clean sort (60x60) - elapsed: 0.009732
Quick sort (60x60) - elapsed: 0.000258
Basic sort (70x70) - elapsed: 0.023101
Clean sort (70x70) - elapsed: 0.016593
Quick sort (70x70) - elapsed: 0.000360
Basic sort (80x80) - elapsed: 0.035169
Clean sort (80x80) - elapsed: 0.027466
Quick sort (80x80) - elapsed: 0.000445
Basic sort (90x90) - elapsed: 0.053590
Clean sort (90x90) - elapsed: 0.039012
Quick sort (90x90) - elapsed: 0.000665
Basic sort (100x100) - elapsed: 0.074192
Clean sort (100x100) - elapsed: 0.053694
Quick sort (100x100) - elapsed: 0.000797
Basic sort (200x200) - elapsed: 0.656721
Clean sort (200x200) - elapsed: 0.478688
Quick sort (200x200) - elapsed: 0.002313
Basic sort (300x300) - elapsed: 2.826153
Clean sort (300x300) - elapsed: 2.126663
Quick sort (300x300) - elapsed: 0.004871
Basic sort (400x400) - elapsed: 8.384908
Clean sort (400x400) - elapsed: 6.374244
Quick sort (400x400) - elapsed: 0.008324
Basic sort (500x500) - elapsed: 22.083337
Clean sort (500x500) - elapsed: 16.124325
Quick sort (500x500) - elapsed: 0.014953
Basic sort (600x600) - elapsed: 43.233985
Clean sort (600x600) - elapsed: 31.362548
Quick sort (600x600) - elapsed: 0.019563
Basic sort (700x700) - elapsed: 85.463261
Clean sort (700x700) - elapsed: 60.488744
Quick sort (700x700) - elapsed: 0.027003
Basic sort (800x800) - elapsed: 148.358024
Clean sort (800x800) - elapsed: 102.991679
Quick sort (800x800) - elapsed: 0.038143
Basic sort (900x900) - elapsed: 253.434539
Clean sort (900x900) - elapsed: 150.658682
Quick sort (900x900) - elapsed: 0.045815
Quick sort (10x10) - elapsed: 0.000007
Quick sort (20x20) - elapsed: 0.000025
Quick sort (30x30) - elapsed: 0.000057
Quick sort (40x40) - elapsed: 0.000104
Quick sort (50x50) - elapsed: 0.000196
Quick sort (60x60) - elapsed: 0.000245
Quick sort (70x70) - elapsed: 0.000397
Quick sort (80x80) - elapsed: 0.000435
Quick sort (90x90) - elapsed: 0.000538
Quick sort (100x100) - elapsed: 0.000676
Quick sort (200x200) - elapsed: 0.002780
Quick sort (300x300) - elapsed: 0.005868
Quick sort (400x400) - elapsed: 0.009393
Quick sort (500x500) - elapsed: 0.016258
Quick sort (600x600) - elapsed: 0.024982
Quick sort (700x700) - elapsed: 0.031137
Quick sort (800x800) - elapsed: 0.042561
Quick sort (900x900) - elapsed: 0.052450
Quick sort (1000x1000) - elapsed: 0.061720
Quick sort (2000x2000) - elapsed: 0.229984
Quick sort (3000x3000) - elapsed: 0.480724
Quick sort (4000x4000) - elapsed: 0.826916
Quick sort (5000x5000) - elapsed: 1.308370
Quick sort (6000x6000) - elapsed: 1.890218
Quick sort (7000x7000) - elapsed: 2.559171
Quick sort (8000x8000) - elapsed: 3.346258
Quick sort (9000x9000) - elapsed: 4.359553
Quick sort (10000x10000) - elapsed: 5.345243
Quick sort (20000x20000) - elapsed: 22.189061
Quick sort (30000x30000) - elapsed: 51.385711
Quick sort (40000x40000) - elapsed: 97.543689
Quick sort (50000x50000) - elapsed: 177.373366
Quick sort (60000x60000) - elapsed: 315.083561
Quick sort (70000x70000) - elapsed: 476.135379
Quick sort (80000x80000) - elapsed: 756.888114
Quick sort (90000x90000) - elapsed: 1002.540185
At the very smallest sizes (10x10 or less), it is possible that the qsort() code is slower than the others — the difference is tiny (a few microseconds) but fairly consistent. By the time you've reached 20x20, the qsort() code is persistently faster, and the discrepancy grows. Note that the size, N, used for O(NlogN) or O(N2), corresponds to the square of the size of the matrix — so the amount of data to be sorted in a 20x20 matrix is four times the amount of data to be sorted in a 10x10 matrix. The performance of the basic sort or 'clean sort' is so bad that a 90k x 90k matrix doesn't bear thinking about, but the qsort() code sorts it in a time comparable to the time taken by the others to sort a 900 x 900 matrix (1/10,000th the size).
Fixing the code added 2018-02-02
The code added to the question on 2018-02-02 is a good attempt at solving the problem in a different way.
As noted by the OP, it sometimes fails to sort the data correctly.
The problem is that the code in the lower triangle
Here's the code fixed so it produces the correct output on the two sample matrices used previously.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
static int a[500][500];
int i, j, l, k, m, b, n, t, d, c;
printf("Unesite n kvadratne matrice:\n");
scanf("%d", &n);
printf("Matrica pre sortiranja\n\n");
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
scanf("%d", &a[i][j]);
}
}
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
printf("%3d", a[i][j]);
printf("\n");
}
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
{
if (i > j) // ispod dijagonale (LT)
{
int s = j + 1; // JL
for (l = i; l < n; l++)
{
//for (k = j; k < l; k++) // OP
for (k = s; k < l; k++) // JL
{
//printf("a[%d][%d] = %d <=> a[%d][%d] %d\n", // JL
// i, j, a[i][j], l, k, a[l][k]); // JL
//if (a[i][j] > a[l][k] && k < l) // OP
if (a[i][j] > a[l][k]) // JL
{
t = a[i][j];
a[i][j] = a[l][k];
a[l][k] = t;
}
}
s = 0; // JL
}
}
if (i < j) // iznad dijagonale (UT)
{
int s = j + 1; // JL
for (m = i; m < n; m++)
{
//for (b = j; b < n; b++) // OP
for (b = s; b < n; b++) // JL
{
//printf("a[%d][%d] = %d <=> a[%d][%d] %d\n", // JL
// i, j, a[i][j], m, b, a[m][b]); // JL
//if (a[i][j] < a[m][b] && m < b) // OP
if (a[i][j] < a[m][b]) // JL
{
t = a[i][j];
a[i][j] = a[m][b];
a[m][b] = t;
}
}
s = m + 2; // JL
}
}
if (i == j) // dijagonala
{
for (d = i; d < n; d++)
{
for (c = d + 1; c < n; c++)
{
if (a[d][d] % 2 != 0 && a[c][c] % 2 == 0)
{
t = a[d][d];
a[d][d] = a[c][c];
a[c][c] = t;
}
}
}
for (d = i; d < n; d++)
{
for (c = d + 1; c < n; c++)
{
if (a[d][d] % 2 == 0 && a[c][c] % 2 == 0
&& a[d][d] > a[c][c])
{
t = a[d][d];
a[d][d] = a[c][c];
a[c][c] = t;
}
else if (a[d][d] % 2 != 0 && a[c][c] % 2
!= 0 && a[d][d] < a[c][c])
{
t = a[d][d];
a[d][d] = a[c][c];
a[c][c] = t;
}
}
}
}
}
}
printf("Posle sortiranja:\n");
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
printf("%3d", a[i][j]);
printf("\n");
}
return 0;
}
The commented out printing operations were crucial to seeing what the trouble was.
Sample output
This program was sort2d-mk2-73.
$ sort2d-mk2-73 < example-2.in
Unesite n kvadratne matrice:
Matrica pre sortiranja
87 32 98 58 60 71 46 81 70 14
22 92 15 98 51 26 94 67 46 56
71 89 86 16 20 89 97 89 45 92
63 13 76 19 75 19 66 89 58 41
82 68 75 26 58 20 89 87 65 66
74 83 68 92 10 98 90 21 39 63
24 65 23 68 62 44 48 22 27 59
26 27 71 71 51 31 43 69 92 10
54 19 41 50 10 89 42 52 94 54
42 50 79 48 77 18 29 40 61 63
Posle sortiranja:
48 98 98 97 94 92 92 90 89 89
10 58 89 89 87 81 75 71 70 67
10 13 86 66 66 65 63 60 59 58
18 19 22 92 58 56 54 51 46 46
23 24 26 26 94 45 41 39 32 27
27 29 31 40 41 98 26 22 21 20
42 42 43 44 48 50 87 20 19 16
50 51 52 54 61 62 63 69 15 14
65 68 68 68 71 71 71 74 63 10
75 76 77 79 82 83 89 89 92 19
$ sort2d-mk2-73 < example-1.in
Unesite n kvadratne matrice:
Matrica pre sortiranja
1 5 4 7 2
4 8 5 9 0
2 7 6 5 3
3 1 7 4 9
2 5 1 7 3
Posle sortiranja:
4 9 9 7 5
1 6 5 5 4
1 2 8 3 2
2 3 4 3 0
5 7 7 7 1
$
For comparison, the code posted in the question (sort2d-mk2-67) generated:
$ sort2d-mk2-67 < example-2.in
Unesite n kvadratne matrice :
Matrica pre sortiranja
Posle sortiranja :
48 98 98 97 94 92 92 90 89 66
10 58 89 89 89 87 81 75 70 63
10 13 86 71 67 66 65 60 59 56
18 19 22 92 58 58 54 51 46 46
23 24 26 29 94 45 41 39 32 27
26 27 31 40 41 98 26 22 21 20
42 42 43 44 48 50 87 20 19 16
50 51 52 54 61 62 63 69 15 14
65 68 68 68 71 71 71 76 63 10
74 75 77 79 82 83 89 89 92 19
$ sort2d-mk2-67 < example-1.in
Unesite n kvadratne matrice :
Matrica pre sortiranja
Posle sortiranja :
4 9 9 7 5
1 6 5 5 3
1 2 8 4 2
2 3 5 3 0
4 7 7 7 1
$
One of the changes between sort2d-mk2-67.c and sort2d-mk2-73.c was compressing the printing; another change was to print the matrix before and after the sorting operation.
In the smaller matrix, you can see that the 3 in row 1 column 4 (counting from 0) should be the 4 in row 2 column 3.
Similarly, the 5 in row 3 column 2 should be the 4 in row 4 column 1.
The fixed code is OK.
I've not benchmarked this code (yet).

Resources