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;
}
}
}
}
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).