Related
I need to store the permutations of four letters in C
i was trying to use this algorithm but no idea how to store the output in some array
if someone can correct this for me or give another algorithm i would appreciate
#include <stdio.h>
#include <string.h>
void swap(char* x, char* y)
{
char temp;
temp = *x;
*x = *y;
*y = temp;
}
void permute(char* a, int l, int r)
{
int i;
if (l == r)
printf("%s\n", a);
else {
for (i = l; i <= r; i++) {
swap((a + l), (a + i));
permute(a, l + 1, r);
swap((a + l), (a + i)); // backtrack
}
}
}
int main()
{
char str[] = "AGTC";
int n = strlen(str);
permute(str, 0, n - 1);
return 0;
}
You should note that you will require quite a large size array to store all the permutations. If you have a 4 byte string, this will be a 2D array of 24*5. So this is only practical if you know ahead of time the max size of the string you want to support.
The code below works for max 4 byte strings. For higher size, you need to increase both the dimensions of the 2D array storage. e.g. for 5 byte it will be 120*6
// global
char store[24][5];
void permute(char* a, int l, int r)
{
int i;
static int storeindex;
if (l == r)
{
strcpy(store[storeindex++],a);
}
else {
for (i = l; i <= r; i++) {
swap((a + l), (a + i));
permute(a, l + 1, r);
swap((a + l), (a + i)); // backtrack
}
}
}
Additional note - The algorithm given above does not print distinct permutations. If the input string has duplicates, this algorithm will print permutations with duplicates. e.g. if input is AAAA output is 24 lines of AAAA
You could do it by using malloc. For this you need to know the number of combinations.
Combination would be factorial of size of string given.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void swap(char* x, char* y)
{
char temp;
temp = *x;
*x = *y;
*y = temp;
}
void permute(char* a, int l, int r, char arr[], int n)
{
int i;
static long count = 0;
if (l == r)
{
//printf("%s\n", a);
memcpy(arr+count*n, a, n);
count++;
}
else {
for (i = l; i <= r; i++) {
swap((a + l), (a + i));
permute(a, l + 1, r, arr, n);
swap((a + l), (a + i)); // backtrack
}
}
}
long factorial(int n)
{
int c = 0;
long fact = 1;
for (c = 1; c <= n; c++)
fact = fact * c;
return fact;
}
int main()
{
char str[] = "AGTC";
int n = strlen(str);
long t_comb = factorial(n);
char *arr = NULL;
char *print = NULL;
arr = (char *)malloc(t_comb * n);
if(arr == NULL)
{
printf("error\n");
}
print = (char *)malloc(n+1);
memset(print, '\0', n+1);
permute(str, 0, n - 1, arr, n);
long itr = 0;
for(itr = 0 ; itr < t_comb ; itr++)
{
memcpy(print, arr+itr*n, n);
printf("%s\n", print);
}
/* After using */
free(print);
free(arr);
return 0;
}
I'm learning heap sort by Cormen.
When I'm trying to run heapsort on the array, there's a problem and the program crashes (segmentation fault). I tried to put some printf's in the heapsort function and printing the h->size and h->count values but they seem to changed in some way from 10 to 3 (!!!) without me touching them (try to print them before the loop in heap_sort and after)..
I really don't understand what is the problem. please help me.
using Eclipse on windows7.
main.c:
#include <stdio.h>
#include "heap.h"
void print_array2(int *a, int n)
{
int *end = a + n;
while (a < end)
printf("%d ", *a++);
printf("\n");
}
int main(void)
{
int a[] =
{ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 };
print_array2(a, 10);
heapsort(a, 10);
print_array2(a, 10);
return 0;
}
heap.c:
#include <stdlib.h>
#include <stdio.h>
#include "heap.h"
void heapify(heap *h, int i)
{
int largest, left = LEFT(i), right = RIGHT(i);
if (left < h->count && (*(h->a + left) > *(h->a + i)))
largest = left;
else
largest = i;
if (right < h->count && (*(h->a + right) > *(h->a + largest)))
largest = right;
if (largest != i)
{
swap(h->a + i, h->a + largest);
heapify(h, largest);
}
}
heap *build_heap(int *a, int size)
{
heap h = (heap
)
{ .size = size, .count = size, .a = a };
heap *ph = &h;
int i = size / 2;
while (i >= 0)
heapify(ph, i--);
return ph;
}
void heapsort(int *a, int size)
{
heap *h = build_heap(a, size);
int i;
for (i = h->size - 1; i >= 1; --i)
{
swap(h->a, h->a + i);
h->count--;
heapify(h, 0);
}
}
void print_heap(heap *h)
{
int *end = h->a + h->count, *arr = h->a;
while (arr < end)
printf("%d ", *arr++);
printf("\n");
}
void print_array(heap *h)
{
int *end = h->a + h->size, *arr = h->a;
while (arr < end)
printf("%d ", *arr++);
printf("\n");
}
static void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
heap.h:
#ifndef HEAP_H_
#define HEAP_H_
typedef struct
{
int size; //array size
int count; //heap size
int *a; //int array
} heap;
#define PARENT(x) ((x + 1) / 2)
#define LEFT(x) (2 * (x) + 1)
#define RIGHT(x) (2 * ( (x) + 1) )
void heapify(heap* h, int i);
heap *build_heap(int *a, int size);
void heapsort(int *a, int size);
void print_heap(heap *h);
void print_array(heap *h);
static void swap(int *a, int *b);
#endif /* HEAP_H_ */
#mafso is correct. I changed build_heap to return a copy of the heap instead of a pointer and it worked. Maybe not the best way but it works. Here is the code:
heap.h
#ifndef HEAP_H_
#define HEAP_H_
typedef struct
{
int size; //array size
int count; //heap size
int *a; //int array
} heap;
#define PARENT(x) ((x + 1) / 2)
#define LEFT(x) (2 * (x) + 1)
#define RIGHT(x) (2 * ( (x) + 1) )
void heapify(heap* h, int i);
heap build_heap(int *a, int size);
void heapsort(int *a, int size);
void print_heap(heap *h);
void print_array(heap *h);
static void swap(int *a, int *b);
#endif /* HEAP_H_ */
heap.c
#include <stdlib.h>
#include <stdio.h>
#include "heap.h"
void heapify(heap *h, int i)
{
int largest, left = LEFT(i), right = RIGHT(i);
if (left < h->count && (*(h->a + left) > *(h->a + i)))
largest = left;
else
largest = i;
if (right < h->count && (*(h->a + right) > *(h->a + largest)))
largest = right;
if (largest != i)
{
swap(h->a + i, h->a + largest);
heapify(h, largest);
}
}
heap build_heap(int *a, int size)
{
heap h;// = (heap) { .size = size, .count = size, .a = a };
h.size = size;
h.count = size;
h.a = a;
heap *ph = &h;
int i = size / 2;
while (i >= 0)
heapify(ph, i--);
return *ph;
}
void heapsort(int *a, int size)
{
heap h = build_heap(a, size);
int i;
for (i = h.size - 1; i >= 1; --i)
{
swap(h.a, h.a + i);
h.count--;
heapify(&h, 0);
}
}
void print_heap(heap *h)
{
int *end = h->a + h->count, *arr = h->a;
while (arr < end)
printf("%d ", *arr++);
printf("\n");
}
void print_array(heap *h)
{
int *end = h->a + h->size, *arr = h->a;
while (arr < end)
printf("%d ", *arr++);
printf("\n");
}
static void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
This was my output:
4 1 3 2 16 9 10 14 8 7
1 2 3 4 7 8 9 10 14 16
I'm not C expert and I've read through the forum, but I still need some advice regarding a sorting problem on C.
I have 4 dynamic arrays of doubles in C. All of them are the same size, and lets say n. What I want to do is to sort all of them using one of the arrays as first order and a second array as my second order. So if the arrays are *x, *y, *w and *z. I want to sort them according to the values of *x, then *y.
I must do this efficiently because the arrays are quite large.
Any help will be much appreciated.
The easy way to do this would be to map your four separate arrays onto a single array of a struct type like
struct rec {
double x;
double y;
double w;
double z;
};
struct rec *arr = malloc( sizeof *arr * N ); // where N is the number of
// elements in each array
if ( !arr )
// malloc failed, handle error somehow
for ( size_t i = 0; i < N; i++ )
{
arr[i].x = x[i];
arr[i].y = y[i];
arr[i].w = w[i];
arr[i].z = z[i];
}
and then create a comparison function to pass to qsort:
int cmpRec( const void *lhs, const void *rhs )
{
struct rec *l = lhs;
struct rec *r = rhs;
if ( l->x < r->x )
return -1;
else if ( l->x > r->x )
return 1;
else
{
if ( l->y < r->y )
return -1;
else if ( l->y > r->y )
return 1;
else
return 0;
}
return 0;
}
Now you can use the qsort library function to sort that array of struct:
qsort( arr, N, sizeof *arr, cmpRec );
Once that array is sorted, you can map the results back onto your four original arrays.
Clearly, sorting this using standard qsort() is not going to work; there isn't a mechanism for passing four arrays.
Equally clearly, if the data were structured as an array of structures, then using qsort() would be feasible.
Question 1: Is it feasible to create an array of structures, load it, sort it, and then unload back into the original arrays?
Question 2: Another option is to sort an array of integers:
int indexes[n];
for (int i = 0; i < n; i++)
indexes[i] = i;
qsort(indexes, n, sizeof(indexes[0]), comparator);
The comparator function would have to be able to access the x and y arrays as file scope variables:
int comparator(void const *v1, void const *v2)
{
int i1 = *(int *)v1;
int i2 = *(int *)v2;
extern double *x, *y;
if (x[i1] > x[i2])
return +1;
else if (x[i1] < x[i2])
return -1;
else if (y[i1] > y[i2])
return +1;
else if (y[i1] < y[i2])
return -1;
else
return 0;
}
You'd then be able to access the arrays using x[indexes[i]] etc to access the ith element in sorted order.
Is that acceptable?
If that is not convenient either, then you will end up writing your own sort; it isn't horribly painful, but will require some care.
I spent some time adapting an existing sort test framework to this scenario. The full code is quite large because it includes a lot of testing support code. The core function (compare, swap, partition and quicksort) are here (122 lines, including comment and blank lines):
/* SO 20271977 - sort arrays x, y, z, w (type double, size n) in parallel based on values in x and y */
/*
** To apply this to the real code, where there are 4 arrays to be sorted
** in parallel, you might write:
**
** Array4 a;
** a.x = x;
** a.y = y;
** a.z = z;
** a.w = w;
** a.n = n;
** quicksort_random(&a);
**
** Or even:
**
** quicksort_random((Array4){ .n = n, .x = x, .y = y, .z = z, .w = w });
**
** combining designated initializers and compound literals. Or you could write a
** trivial wrapper so that you can call:
**
** quicksort_random_wrapper(n, x, y, z, w);
*/
/* SOF so-20271977.h */
#include <stddef.h>
typedef struct Array4
{
size_t n;
double *x;
double *y;
double *z;
double *w;
} Array4;
extern void quicksort_random(Array4 *A);
/* EOF so-20271977.h */
#include <assert.h>
#include <stdlib.h> /* lrand48() */
/*
** Note that a more careful implementation would use nrand48() instead
** of lrand48() to prevent its random number generation from interfering
** with other uses of the x-rand48() functions.
*/
typedef size_t (*Part)(Array4 *A, size_t p, size_t r);
static void quicksort_partition(Array4 *A, size_t p, size_t r, Part partition);
static size_t partition_random(Array4 *A, size_t p, size_t r);
/* Quick Sort Wrapper function - specifying random partitioning */
void quicksort_random(Array4 *A)
{
quicksort_partition(A, 0, A->n - 1, partition_random);
}
/* Main Quick Sort function */
static void quicksort_partition(Array4 *A, size_t p, size_t r, Part partition)
{
if (p < r)
{
size_t q = (*partition)(A, p, r);
assert(p <= q && q <= r);
if (q > 0)
quicksort_partition(A, p, q-1, partition);
quicksort_partition(A, q+1, r, partition);
}
}
static inline int compare(Array4 const *A, size_t p, size_t r)
{
if (A->x[p] < A->x[r])
return -1;
else if (A->x[p] > A->x[r])
return +1;
if (A->y[p] < A->y[r])
return -1;
else if (A->y[p] > A->y[r])
return +1;
else
return 0;
}
static inline size_t random_int(size_t p, size_t r)
{
return(lrand48() % (r - p + 1) + p);
}
static inline void swap(Array4 *A, size_t i, size_t j)
{
double d;
d = A->x[i];
A->x[i] = A->x[j];
A->x[j] = d;
d = A->y[i];
A->y[i] = A->y[j];
A->y[j] = d;
d = A->z[i];
A->z[i] = A->z[j];
A->z[j] = d;
d = A->w[i];
A->w[i] = A->w[j];
A->w[j] = d;
}
static size_t partition_random(Array4 *A, size_t p, size_t r)
{
size_t pivot = random_int(p, r);
swap(A, pivot, r);
size_t i = p-1;
size_t j = p;
while (j <= r)
{
if (compare(A, j, r) <= 0)
swap(A, j, ++i);
j++;
}
return i;
}
The test framework (quite ridiculously elaborate if it weren't that I already had a variant of it on hand) is 369 lines including blank lines and comment lines — and all the code above:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define FLTFMT "%13.6f"
typedef struct Array4
{
size_t n;
double *x;
double *y;
double *z;
double *w;
} Array4;
static int trace = 0;
static void *xmalloc(size_t size)
{
void *space = malloc(size);
if (space == 0)
{
fprintf(stderr, "Out of memory (%zu)\n", size);
exit(1);
}
return space;
}
void quicksort_last(Array4 *A);
void quicksort_random(Array4 *A);
void selectionsort(Array4 *A);
static inline int compare(Array4 const *A, size_t p, size_t r)
{
if (A->x[p] < A->x[r])
return -1;
else if (A->x[p] > A->x[r])
return +1;
if (A->y[p] < A->y[r])
return -1;
else if (A->y[p] > A->y[r])
return +1;
else
return 0;
}
static void dump_array(char const *tag, Array4 const *A)
{
printf("%s [%zu..%zu]:\n", tag, (size_t)0, A->n-1);
for (size_t i = 0; i < A->n; i++)
printf("(" FLTFMT ", " FLTFMT ", " FLTFMT ", " FLTFMT ")\n",
A->x[i], A->y[i], A->z[i], A->w[i]);
}
static void chk_sort(Array4 const *A)
{
for (size_t i = 0; i < A->n - 1; i++)
{
//if (compare(A, i, i+1) > 0)
{
if (A->x[i] > A->x[i+1])
{
printf("Out of order: A.x[%zu] = " FLTFMT ", A.x[%zu] = " FLTFMT "\n",
i, A->x[i], i+1, A->x[i+1]);
}
else if ((A->x[i] == A->x[i+1] && A->y[i] > A->y[i+1]))
{
printf("Out of order: A.x[%zu] = " FLTFMT ", A.x[%zu] = " FLTFMT ", "
"A.y[%zu] = " FLTFMT ", A.y[%zu] = " FLTFMT "\n",
i, A->x[i], i+1, A->x[i+1], i, A->y[i], i+1, A->y[i+1]);
}
}
}
}
static inline void set(Array4 *A, size_t p, double d)
{
A->x[p] = d;
A->y[p] = d + drand48() - 0.5;
A->z[p] = d / 2.0;
A->w[p] = d * 2.0;
}
static void load_random(Array4 *A)
{
size_t size = A->n;
for (size_t i = 0; i < size; i++)
{
A->x[i] = drand48() * size;
A->y[i] = drand48() * size + drand48() - 0.5;
A->z[i] = drand48() * size / 2.0;
A->w[i] = drand48() * size * 2.0;
}
}
static void load_ascending(Array4 *A)
{
for (size_t i = 0; i < A->n; i++)
set(A, i, i);
}
static void load_descending(Array4 *A)
{
for (size_t i = 0; i < A->n; i++)
set(A, i, A->n - i);
}
static void load_uniform(Array4 *A)
{
for (size_t i = 0; i < A->n; i++)
set(A, i, A->n);
}
static void load_organpipe(Array4 *A)
{
for (size_t i = 0; i <= A->n / 2; i++)
set(A, i, i);
for (size_t i = A->n / 2 + 1; i < A->n; i++)
set(A, i, A->n - i);
}
static void load_invorganpipe(Array4 *A)
{
size_t range = A->n / 2;
for (size_t i = 0; i < A->n / 2; i++)
set(A, i, range - i);
for (size_t i = A->n / 2 + 1; i < A->n; i++)
set(A, i, i - range);
}
typedef void (*Load)(Array4 *A);
typedef void (*Sort)(Array4 *A);
typedef size_t (*Part)(Array4 *A, size_t p, size_t r);
static void test_one_sort(Array4 *A, Sort sort, char const *s_tag,
char const *l_tag, char const *z_tag)
{
if (trace)
{
printf("%s-%s-%s:", z_tag, l_tag, s_tag);
dump_array("Before", A);
}
clock_t start = clock();
(*sort)(A);
clock_t finish = clock();
double sec = (finish - start) / (double)CLOCKS_PER_SEC;
printf("%s-%s-%s: %13.6f\n", z_tag, l_tag, s_tag, sec);
chk_sort(A);
if (trace)
{
printf("%s-%s-%s:", z_tag, l_tag, s_tag);
dump_array("After", A);
}
fflush(stdout);
}
static Array4 *alloc_array(size_t size)
{
Array4 *A = xmalloc(sizeof(*A));
A->n = size;
A->x = xmalloc(size * sizeof(A->x[0]));
A->y = xmalloc(size * sizeof(A->y[0]));
A->z = xmalloc(size * sizeof(A->z[0]));
A->w = xmalloc(size * sizeof(A->w[0]));
return A;
}
static Array4 *dup_array(Array4 *A)
{
size_t size = A->n;
Array4 *B = alloc_array(size);
if (B != 0)
{
B->n = size;
memmove(B->x, A->x, size * sizeof(A->x[0]));
memmove(B->y, A->y, size * sizeof(A->y[0]));
memmove(B->z, A->z, size * sizeof(A->z[0]));
memmove(B->w, A->w, size * sizeof(A->w[0]));
}
return B;
}
static void free_array(Array4 *A)
{
free(A->x);
free(A->y);
free(A->z);
free(A->w);
free(A);
}
static void test_set_sorts(Array4 *A, char const *l_tag, char const *z_tag)
{
struct sorter
{
Sort function;
char const *tag;
} sort[] =
{
{ quicksort_last, "QS.L" },
{ quicksort_random, "QS.R" },
{ selectionsort, "SS.N" },
};
enum { NUM_SORTS = sizeof(sort) / sizeof(sort[0]) };
for (int i = 0; i < NUM_SORTS; i++)
{
Array4 *B = dup_array(A);
test_one_sort(B, sort[i].function, sort[i].tag, l_tag, z_tag);
free(B);
}
}
static void test_set_loads(size_t size, char const *z_tag)
{
struct loader
{
Load function;
char const *tag;
} load[] =
{
{ load_random, "R" },
{ load_ascending, "A" },
{ load_descending, "D" },
{ load_organpipe, "O" },
{ load_invorganpipe, "I" },
{ load_uniform, "U" },
};
enum { NUM_LOADS = sizeof(load) / sizeof(load[0]) };
Array4 *A = alloc_array(size);
for (int i = 0; i < NUM_LOADS; i++)
{
load[i].function(A);
test_set_sorts(A, load[i].tag, z_tag);
}
free_array(A);
}
/* Main Quick Sort function */
static void quicksort_partition(Array4 *A, size_t p, size_t r, Part partition)
{
if (p < r)
{
size_t q = (*partition)(A, p, r);
assert(p <= q && q <= r);
if (q > 0)
quicksort_partition(A, p, q-1, partition);
quicksort_partition(A, q+1, r, partition);
}
}
static size_t partition_random(Array4 *A, size_t p, size_t r);
static size_t partition_last(Array4 *A, size_t p, size_t r);
/* Quick Sort Wrapper function - specifying random partitioning */
void quicksort_random(Array4 *A)
{
quicksort_partition(A, 0, A->n - 1, partition_random);
}
/* Quick Sort Wrapper function - specifying partitioning about last element */
void quicksort_last(Array4 *A)
{
quicksort_partition(A, 0, A->n - 1, partition_last);
}
static inline size_t random_int(size_t p, size_t r)
{
return(lrand48() % (r - p + 1) + p);
}
static inline void swap(Array4 *A, size_t i, size_t j)
{
double d;
d = A->x[i];
A->x[i] = A->x[j];
A->x[j] = d;
d = A->y[i];
A->y[i] = A->y[j];
A->y[j] = d;
d = A->z[i];
A->z[i] = A->z[j];
A->z[j] = d;
d = A->w[i];
A->w[i] = A->w[j];
A->w[j] = d;
}
static size_t partition_random(Array4 *A, size_t p, size_t r)
{
size_t pivot = random_int(p, r);
swap(A, pivot, r);
size_t i = p-1;
size_t j = p;
while (j <= r)
{
if (compare(A, j, r) <= 0)
swap(A, j, ++i);
j++;
}
return i;
}
static size_t partition_last(Array4 *A, size_t p, size_t r)
{
size_t i = p-1;
size_t j = p;
while (j <= r)
{
if (compare(A, j, r) <= 0)
swap(A, j, ++i);
j++;
}
return i;
}
/* Selection Sort algorithm */
void selectionsort(Array4 *A)
{
size_t r = A->n;
for (size_t p = 0; p < r; p++)
{
for (size_t i = p; i < r; i++)
{
if (compare(A, p, i) > 0)
swap(A, p, i);
}
}
}
/*
** To apply this to the real code, where there are 4 arrays to be sorted
** in parallel, you might write:
**
** Array4 a;
** a.x = x;
** a.y = y;
** a.z = z;
** a.w = w;
** a.n = n;
** quicksort_random(&a);
**
** Or even:
**
** quicksort_random((Array4){ .n = n, .x = x, .y = y, .z = z, .w = w });
**
** combining designated initializers and compound literals. Or you could write a
** trivial wrapper so that you can call:
**
** quicksort_random_wrapper(n, x, y, z, w);
*/
int main(void)
{
srand48((long)time(0));
for (size_t i = 10; i <= 40; i += 10)
{
char buffer[10];
snprintf(buffer, sizeof(buffer), "%zuK", i);
test_set_loads(1000*i, buffer);
}
return 0;
}
If you can't use qsort with
typedef struct Point {
double x;
double y;
double w;
double z;
} Point;
Use qsort with
typedef struct UglyThing {
double x;
int i;
} UglyThing;
Create an array of size n, fill x with x values, i with index.
Call qsort. At the end, i will store the permutation order.
Swap the three other arrays according to the permutation order.
Then do the same with little arrays ("with same x") in the y direction.
If this ugly trick is not possible, then I don't see any other solution than reinventing the wheel.
(edit : I have just seen Andrew said something very close to this answer...sorry!)
Bye,
Francis
I'm not C expert and I've read through the forum, but I still need some advice regarding a sorting problem on C.
I have 4 dynamic arrays of doubles in C. All of them are the same size, and lets say n. What I want to do is to sort all of them using one of the arrays as first order and a second array as my second order. So if the arrays are *x, *y, *w and *z. I want to sort them according to the values of *x, then *y.
I must do this efficiently because the arrays are quite large.
Any help will be much appreciated.
The easy way to do this would be to map your four separate arrays onto a single array of a struct type like
struct rec {
double x;
double y;
double w;
double z;
};
struct rec *arr = malloc( sizeof *arr * N ); // where N is the number of
// elements in each array
if ( !arr )
// malloc failed, handle error somehow
for ( size_t i = 0; i < N; i++ )
{
arr[i].x = x[i];
arr[i].y = y[i];
arr[i].w = w[i];
arr[i].z = z[i];
}
and then create a comparison function to pass to qsort:
int cmpRec( const void *lhs, const void *rhs )
{
struct rec *l = lhs;
struct rec *r = rhs;
if ( l->x < r->x )
return -1;
else if ( l->x > r->x )
return 1;
else
{
if ( l->y < r->y )
return -1;
else if ( l->y > r->y )
return 1;
else
return 0;
}
return 0;
}
Now you can use the qsort library function to sort that array of struct:
qsort( arr, N, sizeof *arr, cmpRec );
Once that array is sorted, you can map the results back onto your four original arrays.
Clearly, sorting this using standard qsort() is not going to work; there isn't a mechanism for passing four arrays.
Equally clearly, if the data were structured as an array of structures, then using qsort() would be feasible.
Question 1: Is it feasible to create an array of structures, load it, sort it, and then unload back into the original arrays?
Question 2: Another option is to sort an array of integers:
int indexes[n];
for (int i = 0; i < n; i++)
indexes[i] = i;
qsort(indexes, n, sizeof(indexes[0]), comparator);
The comparator function would have to be able to access the x and y arrays as file scope variables:
int comparator(void const *v1, void const *v2)
{
int i1 = *(int *)v1;
int i2 = *(int *)v2;
extern double *x, *y;
if (x[i1] > x[i2])
return +1;
else if (x[i1] < x[i2])
return -1;
else if (y[i1] > y[i2])
return +1;
else if (y[i1] < y[i2])
return -1;
else
return 0;
}
You'd then be able to access the arrays using x[indexes[i]] etc to access the ith element in sorted order.
Is that acceptable?
If that is not convenient either, then you will end up writing your own sort; it isn't horribly painful, but will require some care.
I spent some time adapting an existing sort test framework to this scenario. The full code is quite large because it includes a lot of testing support code. The core function (compare, swap, partition and quicksort) are here (122 lines, including comment and blank lines):
/* SO 20271977 - sort arrays x, y, z, w (type double, size n) in parallel based on values in x and y */
/*
** To apply this to the real code, where there are 4 arrays to be sorted
** in parallel, you might write:
**
** Array4 a;
** a.x = x;
** a.y = y;
** a.z = z;
** a.w = w;
** a.n = n;
** quicksort_random(&a);
**
** Or even:
**
** quicksort_random((Array4){ .n = n, .x = x, .y = y, .z = z, .w = w });
**
** combining designated initializers and compound literals. Or you could write a
** trivial wrapper so that you can call:
**
** quicksort_random_wrapper(n, x, y, z, w);
*/
/* SOF so-20271977.h */
#include <stddef.h>
typedef struct Array4
{
size_t n;
double *x;
double *y;
double *z;
double *w;
} Array4;
extern void quicksort_random(Array4 *A);
/* EOF so-20271977.h */
#include <assert.h>
#include <stdlib.h> /* lrand48() */
/*
** Note that a more careful implementation would use nrand48() instead
** of lrand48() to prevent its random number generation from interfering
** with other uses of the x-rand48() functions.
*/
typedef size_t (*Part)(Array4 *A, size_t p, size_t r);
static void quicksort_partition(Array4 *A, size_t p, size_t r, Part partition);
static size_t partition_random(Array4 *A, size_t p, size_t r);
/* Quick Sort Wrapper function - specifying random partitioning */
void quicksort_random(Array4 *A)
{
quicksort_partition(A, 0, A->n - 1, partition_random);
}
/* Main Quick Sort function */
static void quicksort_partition(Array4 *A, size_t p, size_t r, Part partition)
{
if (p < r)
{
size_t q = (*partition)(A, p, r);
assert(p <= q && q <= r);
if (q > 0)
quicksort_partition(A, p, q-1, partition);
quicksort_partition(A, q+1, r, partition);
}
}
static inline int compare(Array4 const *A, size_t p, size_t r)
{
if (A->x[p] < A->x[r])
return -1;
else if (A->x[p] > A->x[r])
return +1;
if (A->y[p] < A->y[r])
return -1;
else if (A->y[p] > A->y[r])
return +1;
else
return 0;
}
static inline size_t random_int(size_t p, size_t r)
{
return(lrand48() % (r - p + 1) + p);
}
static inline void swap(Array4 *A, size_t i, size_t j)
{
double d;
d = A->x[i];
A->x[i] = A->x[j];
A->x[j] = d;
d = A->y[i];
A->y[i] = A->y[j];
A->y[j] = d;
d = A->z[i];
A->z[i] = A->z[j];
A->z[j] = d;
d = A->w[i];
A->w[i] = A->w[j];
A->w[j] = d;
}
static size_t partition_random(Array4 *A, size_t p, size_t r)
{
size_t pivot = random_int(p, r);
swap(A, pivot, r);
size_t i = p-1;
size_t j = p;
while (j <= r)
{
if (compare(A, j, r) <= 0)
swap(A, j, ++i);
j++;
}
return i;
}
The test framework (quite ridiculously elaborate if it weren't that I already had a variant of it on hand) is 369 lines including blank lines and comment lines — and all the code above:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define FLTFMT "%13.6f"
typedef struct Array4
{
size_t n;
double *x;
double *y;
double *z;
double *w;
} Array4;
static int trace = 0;
static void *xmalloc(size_t size)
{
void *space = malloc(size);
if (space == 0)
{
fprintf(stderr, "Out of memory (%zu)\n", size);
exit(1);
}
return space;
}
void quicksort_last(Array4 *A);
void quicksort_random(Array4 *A);
void selectionsort(Array4 *A);
static inline int compare(Array4 const *A, size_t p, size_t r)
{
if (A->x[p] < A->x[r])
return -1;
else if (A->x[p] > A->x[r])
return +1;
if (A->y[p] < A->y[r])
return -1;
else if (A->y[p] > A->y[r])
return +1;
else
return 0;
}
static void dump_array(char const *tag, Array4 const *A)
{
printf("%s [%zu..%zu]:\n", tag, (size_t)0, A->n-1);
for (size_t i = 0; i < A->n; i++)
printf("(" FLTFMT ", " FLTFMT ", " FLTFMT ", " FLTFMT ")\n",
A->x[i], A->y[i], A->z[i], A->w[i]);
}
static void chk_sort(Array4 const *A)
{
for (size_t i = 0; i < A->n - 1; i++)
{
//if (compare(A, i, i+1) > 0)
{
if (A->x[i] > A->x[i+1])
{
printf("Out of order: A.x[%zu] = " FLTFMT ", A.x[%zu] = " FLTFMT "\n",
i, A->x[i], i+1, A->x[i+1]);
}
else if ((A->x[i] == A->x[i+1] && A->y[i] > A->y[i+1]))
{
printf("Out of order: A.x[%zu] = " FLTFMT ", A.x[%zu] = " FLTFMT ", "
"A.y[%zu] = " FLTFMT ", A.y[%zu] = " FLTFMT "\n",
i, A->x[i], i+1, A->x[i+1], i, A->y[i], i+1, A->y[i+1]);
}
}
}
}
static inline void set(Array4 *A, size_t p, double d)
{
A->x[p] = d;
A->y[p] = d + drand48() - 0.5;
A->z[p] = d / 2.0;
A->w[p] = d * 2.0;
}
static void load_random(Array4 *A)
{
size_t size = A->n;
for (size_t i = 0; i < size; i++)
{
A->x[i] = drand48() * size;
A->y[i] = drand48() * size + drand48() - 0.5;
A->z[i] = drand48() * size / 2.0;
A->w[i] = drand48() * size * 2.0;
}
}
static void load_ascending(Array4 *A)
{
for (size_t i = 0; i < A->n; i++)
set(A, i, i);
}
static void load_descending(Array4 *A)
{
for (size_t i = 0; i < A->n; i++)
set(A, i, A->n - i);
}
static void load_uniform(Array4 *A)
{
for (size_t i = 0; i < A->n; i++)
set(A, i, A->n);
}
static void load_organpipe(Array4 *A)
{
for (size_t i = 0; i <= A->n / 2; i++)
set(A, i, i);
for (size_t i = A->n / 2 + 1; i < A->n; i++)
set(A, i, A->n - i);
}
static void load_invorganpipe(Array4 *A)
{
size_t range = A->n / 2;
for (size_t i = 0; i < A->n / 2; i++)
set(A, i, range - i);
for (size_t i = A->n / 2 + 1; i < A->n; i++)
set(A, i, i - range);
}
typedef void (*Load)(Array4 *A);
typedef void (*Sort)(Array4 *A);
typedef size_t (*Part)(Array4 *A, size_t p, size_t r);
static void test_one_sort(Array4 *A, Sort sort, char const *s_tag,
char const *l_tag, char const *z_tag)
{
if (trace)
{
printf("%s-%s-%s:", z_tag, l_tag, s_tag);
dump_array("Before", A);
}
clock_t start = clock();
(*sort)(A);
clock_t finish = clock();
double sec = (finish - start) / (double)CLOCKS_PER_SEC;
printf("%s-%s-%s: %13.6f\n", z_tag, l_tag, s_tag, sec);
chk_sort(A);
if (trace)
{
printf("%s-%s-%s:", z_tag, l_tag, s_tag);
dump_array("After", A);
}
fflush(stdout);
}
static Array4 *alloc_array(size_t size)
{
Array4 *A = xmalloc(sizeof(*A));
A->n = size;
A->x = xmalloc(size * sizeof(A->x[0]));
A->y = xmalloc(size * sizeof(A->y[0]));
A->z = xmalloc(size * sizeof(A->z[0]));
A->w = xmalloc(size * sizeof(A->w[0]));
return A;
}
static Array4 *dup_array(Array4 *A)
{
size_t size = A->n;
Array4 *B = alloc_array(size);
if (B != 0)
{
B->n = size;
memmove(B->x, A->x, size * sizeof(A->x[0]));
memmove(B->y, A->y, size * sizeof(A->y[0]));
memmove(B->z, A->z, size * sizeof(A->z[0]));
memmove(B->w, A->w, size * sizeof(A->w[0]));
}
return B;
}
static void free_array(Array4 *A)
{
free(A->x);
free(A->y);
free(A->z);
free(A->w);
free(A);
}
static void test_set_sorts(Array4 *A, char const *l_tag, char const *z_tag)
{
struct sorter
{
Sort function;
char const *tag;
} sort[] =
{
{ quicksort_last, "QS.L" },
{ quicksort_random, "QS.R" },
{ selectionsort, "SS.N" },
};
enum { NUM_SORTS = sizeof(sort) / sizeof(sort[0]) };
for (int i = 0; i < NUM_SORTS; i++)
{
Array4 *B = dup_array(A);
test_one_sort(B, sort[i].function, sort[i].tag, l_tag, z_tag);
free(B);
}
}
static void test_set_loads(size_t size, char const *z_tag)
{
struct loader
{
Load function;
char const *tag;
} load[] =
{
{ load_random, "R" },
{ load_ascending, "A" },
{ load_descending, "D" },
{ load_organpipe, "O" },
{ load_invorganpipe, "I" },
{ load_uniform, "U" },
};
enum { NUM_LOADS = sizeof(load) / sizeof(load[0]) };
Array4 *A = alloc_array(size);
for (int i = 0; i < NUM_LOADS; i++)
{
load[i].function(A);
test_set_sorts(A, load[i].tag, z_tag);
}
free_array(A);
}
/* Main Quick Sort function */
static void quicksort_partition(Array4 *A, size_t p, size_t r, Part partition)
{
if (p < r)
{
size_t q = (*partition)(A, p, r);
assert(p <= q && q <= r);
if (q > 0)
quicksort_partition(A, p, q-1, partition);
quicksort_partition(A, q+1, r, partition);
}
}
static size_t partition_random(Array4 *A, size_t p, size_t r);
static size_t partition_last(Array4 *A, size_t p, size_t r);
/* Quick Sort Wrapper function - specifying random partitioning */
void quicksort_random(Array4 *A)
{
quicksort_partition(A, 0, A->n - 1, partition_random);
}
/* Quick Sort Wrapper function - specifying partitioning about last element */
void quicksort_last(Array4 *A)
{
quicksort_partition(A, 0, A->n - 1, partition_last);
}
static inline size_t random_int(size_t p, size_t r)
{
return(lrand48() % (r - p + 1) + p);
}
static inline void swap(Array4 *A, size_t i, size_t j)
{
double d;
d = A->x[i];
A->x[i] = A->x[j];
A->x[j] = d;
d = A->y[i];
A->y[i] = A->y[j];
A->y[j] = d;
d = A->z[i];
A->z[i] = A->z[j];
A->z[j] = d;
d = A->w[i];
A->w[i] = A->w[j];
A->w[j] = d;
}
static size_t partition_random(Array4 *A, size_t p, size_t r)
{
size_t pivot = random_int(p, r);
swap(A, pivot, r);
size_t i = p-1;
size_t j = p;
while (j <= r)
{
if (compare(A, j, r) <= 0)
swap(A, j, ++i);
j++;
}
return i;
}
static size_t partition_last(Array4 *A, size_t p, size_t r)
{
size_t i = p-1;
size_t j = p;
while (j <= r)
{
if (compare(A, j, r) <= 0)
swap(A, j, ++i);
j++;
}
return i;
}
/* Selection Sort algorithm */
void selectionsort(Array4 *A)
{
size_t r = A->n;
for (size_t p = 0; p < r; p++)
{
for (size_t i = p; i < r; i++)
{
if (compare(A, p, i) > 0)
swap(A, p, i);
}
}
}
/*
** To apply this to the real code, where there are 4 arrays to be sorted
** in parallel, you might write:
**
** Array4 a;
** a.x = x;
** a.y = y;
** a.z = z;
** a.w = w;
** a.n = n;
** quicksort_random(&a);
**
** Or even:
**
** quicksort_random((Array4){ .n = n, .x = x, .y = y, .z = z, .w = w });
**
** combining designated initializers and compound literals. Or you could write a
** trivial wrapper so that you can call:
**
** quicksort_random_wrapper(n, x, y, z, w);
*/
int main(void)
{
srand48((long)time(0));
for (size_t i = 10; i <= 40; i += 10)
{
char buffer[10];
snprintf(buffer, sizeof(buffer), "%zuK", i);
test_set_loads(1000*i, buffer);
}
return 0;
}
If you can't use qsort with
typedef struct Point {
double x;
double y;
double w;
double z;
} Point;
Use qsort with
typedef struct UglyThing {
double x;
int i;
} UglyThing;
Create an array of size n, fill x with x values, i with index.
Call qsort. At the end, i will store the permutation order.
Swap the three other arrays according to the permutation order.
Then do the same with little arrays ("with same x") in the y direction.
If this ugly trick is not possible, then I don't see any other solution than reinventing the wheel.
(edit : I have just seen Andrew said something very close to this answer...sorry!)
Bye,
Francis
I have a generic quicksort function:
void qsort(void* sup,int n,
int(*cmp) (void *x,void *y),
void (*swap) (void *a,void *b))
{
int pv=n/2,l=0,h=n-1;
if(n<2)
return;
while(h-1>=l)
{
if(l==pv)
{
swap(sup+pv,sup+pv+1);
pv++;
}
if(h==pv)
{
swap(sup+pv,sup+(pv-1));
pv--;
}
if(cmp(sup+h, sup+pv))
{
h--;
continue;
}
if(cmp(sup+pv, sup+l))
{
l++;
continue;
}
swap(sup+l,sup+h);
l++,h--;
}
qsort(sup, l, cmp, swap);
qsort(sup+l,n-l, cmp, swap);
}
with these function as parameter:
int cmp(int *c1, int *c2) {
return *c1 > *c2;
}
void swap(int *a,int *b)
{
int c= *a;
*a=*b;
*b=c;
}
the main function is the following:
int main()
{
int arr[4] = {3,4,1,2};
print(arr, 4);
printf("\n\n");
qsort(arr, 4, &cmp, &swap);
print(arr, 4);
return 0;
}
where print is:
void print(int* arr, int size) {
int i = 0;
for(; i < size; ++i) {
printf("%d \t", arr[i]);
}
}
The problem:
When the prototype of qsort is:
void qsort(int* sup,int n,
int(*cmp) (void *x,void *y),
void (*swap) (void *a,void *b))
it works great,
but when I change the sup parameter to void*:
void qsort(void* sup,int n,
int(*cmp) (void *x,void *y),
void (*swap) (void *a,void *b))
it doesn't work. do anybody have any idea why?
I'm working with Code::Blocks under Windows, with MinGW.
You must be able to dereference your parameters. void* cannot be dereferenced as the compiler cannot determine the type you are passing. You must use explicit casting if you pass void*.
This
void qsort(int* sup,int n,
int(*cmp) (void *x,void *y),
void (*swap) (void *a,void *b))
is absolutely fine, but here
void qsort(void* sup,int n,
int(*cmp) (void *x,void *y),
void (*swap) (void *a,void *b))
you are passing a void* (sup) and this one cannot be dereferenced. So your first solution is fine but you must either typecast in (*cmp) or define a qsort for every type.
Here's how you could fix the sort:
#include <stdio.h>
void Qsort(
void* sup,
int n,
int size,
int(*cmp) (const void *x, const void *y),
void (*swap) (void *a,void *b))
{
int pv = n / 2, l = 0, h = n - 1;
if (n < 2)
return;
while (h - 1 >= l)
{
if (l == pv)
{
swap((char*)sup + pv * size, (char*)sup + (pv + 1) * size);
pv++;
}
if(h == pv)
{
swap((char*)sup + pv * size, (char*)sup + (pv - 1) * size);
pv--;
}
if (cmp((char*)sup + h * size, (char*)sup + pv * size) > 0)
{
h--;
continue;
}
if (cmp((char*)sup + pv * size, (char*)sup + l * size) > 0)
{
l++;
continue;
}
swap((char*)sup + l * size, (char*)sup + h * size);
l++, h--;
}
Qsort(sup, l, size, cmp, swap);
Qsort((char*)sup + l * size, n - l, size, cmp, swap);
}
int cmp(const void *c1, const void *c2)
{
int a = *(const int*)c1;
int b = *(const int*)c2;
if (a > b) return 1;
if (a < b) return -1;
return 0;
}
void swap(void *c1, void *c2)
{
int c = *(int*)c1;
*(int*)c1 = *(int*)c2;
*(int*)c2 = c;
}
void print(int* arr, int size)
{
int i = 0;
for(; i < size; ++i)
{
printf("%d \t", arr[i]);
}
}
int main(void)
{
int arr[4] = {3,4,1,2};
print(arr, 4);
printf("\n\n");
Qsort(arr, 4, sizeof(arr[0]), &cmp, &swap);
print(arr, 4);
return 0;
}
Output (ideone):
3 4 1 2
1 2 3 4
Note that naming your functions the same way as standard library functions is a bad thing to do. Your program might fail to compile or work. For this reason I changed qsort to Qsort.
we can improve a generic quick sort to omit swap function.
#ifdef _WIN32
#define alloca _alloca
#else
#include <alloca.h>
#endif
// the generic swap function
void arrswap(void * const a, void * const b, int const sz) {
int64_t tmp;
void * p;
bool needfree = false;
if (sz > sizeof(int64_t)) {
p = alloca(sz);
if (p == NULL) {
p = malloc(sz);
//assert(p != NULL, "not enough memory");
needfree = true;
}
}
else {
p = &tmp;
}
memcpy(p, b, sz);
memcpy(b, a, sz);
memcpy(a, p, sz);
if (needfree) {
free(p);
}
}
// O(n^2) sort
void arrsort(void * const p, int const sz, int const n,
int(*compare)(void const * const pa, void const *const pb)) {
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (compare((char*)p + i*sz, (char*)p + j*sz) == 1) {
arrswap((char*)p + i*sz, (char*)p + j*sz, sz);
}
}
}
}
// guess the index of the pivot value from three value in the array.
static int guessmidval(void * const p, int const sz, int const n,
int(*compare)(void const * const pa, void const *const pb)) {
int a = 0;
int b = n / 2;
int c = n - 1;
int ab = compare((char*)p + a*sz, (char*)p + b*sz);
int bc = compare((char*)p + b*sz, (char*)p + c*sz);
int cb = compare((char*)p + c*sz, (char*)p + b*sz);
int ba = compare((char*)p + b*sz, (char*)p + a*sz);
if (ab <= 0 && bc <= 0 || cb <= 0 && ba <= 0) {
return b;
}
int ac = compare((char*)p + a*sz, (char*)p + c*sz);
int ca = compare((char*)p + c*sz, (char*)p + a*sz);
if (ba <= 0 && ac <= 0 || ca <= 0 && ab <= 0) {
return a;
}
return c;
}
// quick sort
void arrqsort(void * const p, int sz, int const n,
int(*compare)(void const * const pa, void const *const pb)) {
if (n <= 2) {
arrsort(p, sz, n, compare);
return;
}
int midval_index = guessmidval(p, sz, n, compare);
arrswap(p, (char*)p + midval_index*sz, sz);
int i, j;
for (i = 1, j = n - 1; ; i++, j--) {
for (; compare((char*)p + i*sz, p) <= -1 && i <= j; i++);
for (; compare((char*)p + j*sz, p) >= +1 && i <= j; j--);
if (i >= j)break;
arrswap((char*)p + i*sz, (char*)p + j*sz, sz);
}
arrqsort(p, sz, i, compare);
arrqsort((char*)p + i*sz, sz, n - i, compare);
}
creating a compare function for int64:
int compare_int64(void const * const pa, void const *const pb) {
int64_t a = *(int64_t*)pa;
int64_t b = *(int64_t*)pb;
if (a > b)return 1;
else if (a < b)return -1;
return 0;
}
we can call arrqsort like :
int64_t a[] = { 3,1,65,4,-1 };
int n = sizeof(a) / sizeof(*a);
arrqsort(a, sizeof(*a), n, compare_int64);
for (int j = 0; j < n; j++) {//-1,1,3,4,65,
printf("%d,", a[j]);
}