I have an array of 3 floating point values:
float norms[3];
norms[0] = 0.4;
norms[1] = 3.2;
norms[2] = 1.7;
I want to sort this array in descending order while keeping track of the original indexes of the values in the array.
In other words, given the array norms[] = {0.4, 3.2, 1.7} with corresponding indices {0, 1, 2}, I basically want to obtain an array of corresponding ints that reflects the original positions of the float values in norms[] following a descending sort. In this case it would be {1, 2, 0}.
What is the best/cleanest way to achieve this?
Use a structure to store the value as well as index and then sort according to value.
struct str
{
float value;
int index;
};
int cmp(const void *a, const void *b)
{
struct str *a1 = (struct str *)a;
struct str *a2 = (struct str *)b;
if ((*a1).value > (*a2).value)
return -1;
else if ((*a1).value < (*a2).value)
return 1;
else
return 0;
}
int main()
{
float arr[3] = {0.4, 3.12, 1.7};
struct str objects[3];
for (int i = 0; i < 3; i++)
{
objects[i].value = arr[i];
objects[i].index = i;
}
//sort objects array according to value maybe using qsort
qsort(objects, 3, sizeof(objects[0]), cmp);
for (int i = 0; i < 3; i++)
printf("%d ", objects[i].index); //will give 1 2 0
// your code goes here
return 0;
}
Just use any sorting algorithm 'aliasing' the original array access. Example with bubblesort
int len = 3;
bool switched = false;
float myFloatArr[3];
int myFloatIndex[3] = {0, 1, 2};
do
{
switched = false;
for(i = 1; i < len; i++)
{
if(myFloatArr[myFloatIndex[i - 1]] < myFloatArr[myFloatIndex[i]])
{
int temp = myFloatIndex[i];
myFloatIndex[i] = myFloatIndex[i - 1];
myFloatIndex[i - 1] = temp;
switched = true;
}
}
}
while(switched);
The cleanest way i can think of is to create a structure which contains both float and index.
typedef struct str {
float val;
int index;
} str;
then create an array of this structure and sort it according to val.
Related
I was trying to solve below problem:
Given two integer arrays nums1 and nums2, return an array of their intersection. Each element in the result must appear as many times as it shows in both arrays and you may return the result in any order.
Example 1:
Input: nums1 = [1,2,2,1], nums2 = [2,2]
Output: [2,2]
Here is my code:
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* intersect(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){
for(int i=0; i<nums1Size-1; i++){
if(nums1[i]>nums1[i+1]){
int temp = nums1[i];
nums1[i] = nums1[i+1];
nums1[i+1] = temp;
i = -1;
}
}
for(int i=0; i<nums2Size-1; i++){
if(nums2[i]>nums2[i+1]){
int temp = nums2[i];
nums2[i] = nums2[i+1];
nums2[i+1] = temp;
i = -1;
}
}
int i = 0;
int j = 0;
int* res = (int*)malloc(10* sizeof(int));
int k = 0;
if(!(nums1Size > nums2Size)){
int * temp = nums1;
nums1 = nums2;
nums2 = temp;
int tempint = nums1Size;
nums1Size = nums2Size;
nums2Size = tempint;
}
while(i<nums1Size && j<nums2Size){
if(nums1[i] > nums2[j]){
j++;
}
else if(nums1[i] < nums2[j]){
i++;
}
else{
res[k++] = nums1[i];
i++; j++;
}
}
*returnSize = sizeof(res)/sizeof(res[0]);
return res;
}
To simplify the problem you have to solve, let's first write a helper function that counts the number of occurrences of a particular element inside an array:
int count_elem(int* arr, int n, int elem) {
int count = 0;
for (int i = 0; i < n; i += 1) {
if (arr[i] == elem) {
count += 1;
}
}
return count;
}
Now, let's try to solve the problem following the problem description:
int* intersect(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize) {
// here we allocate `res` with size of the biggest array, because that's the worst case we'll have
int* res = malloc(sizeof(int) * ((nums1Size > nums2Size) ? nums1Size : nums2Size));
// just to be sure `malloc()` did not return an error
if (res == NULL) {
return NULL;
}
// we'll keep track of how many elements we actually put inside `res`
*returnSize = 0;
// let's loop through all elements of `nums1`
for (int i = 0; i < nums1Size; i += 1) {
int elem = nums1[i];
// if we already put the element inside `res`, we skip this cycle
int count_res = count_elem(res, *returnSize, elem);
if (count_res > 0) {
continue;
}
// let's count the occurrences in both arrays
int count1 = count_elem(nums1, nums1Size, elem);
int count2 = count_elem(nums2, nums2Size, elem);
// let's calculate how many times the element must be present inside `res`
// i.e.: the same number of times of the array with the fewer occurrences of it
// NOTE: if `nums1` or `nums2` do not include the element, we also don't include it inside `res`
int count_min = (count1 < count2) ? count1 : count2;
// now let's put inside `res` as many times as we previously calculated
for (int i = 0; i < count_min; i += 1) {
res[*returnSize] = elem;
*returnSize += 1;
}
}
return res;
}
Let's try if it works:
int main(void) {
int arr1[] = {1, 2, 2, 1};
int arr2[] = {2, 2};
int res_size;
int* res = intersect(arr1, sizeof(arr1) / sizeof(arr1[0]), arr2, sizeof(arr2) / sizeof(arr2[0]), &res_size);
// let's print the result of `intersect()`
for (int i = 0; i < res_size; i += 1) {
printf("%d\n", res[i]);
}
return 0;
}
Output:
2
2
NOTE: the function is not optimized for speed nor for memory efficiency. This will be left as an exercise for the reader.
UPDATE
The previous version of the answer was wrong (sorry again). Now it should be correct.
Is it possible to extend a static array in C?
I tried creating a function which allocates a new dynamic array, copies contents to it and returns it's pointer; but It didn't work correctly, I'm getting debug error everytime.
I need to do something like this;
int a1[5] = { 1,2,5,4,1 };
extend(a1); //or a1* = extend(a1);
.
.
.
a1[9] = 2;
My extend function so far;
int extend(int x[], int oldSize, int newSize) {
int *extendedX = (int*)calloc(newSize, sizeof(int));
int i = 0;
for (; i < oldSize;i++) {
extendedX[i] = x[i];
}
for (; i < newSize; i++) {
extendedX[i] = 0;
}
return *extendedX;
}
extend(a1); //or a1* = extend(a1);
Your function extend needs to return int * instead of just int.
int* extend(int x[], int oldSize, int newSize);
Also, you need to create a new pointer a2 to be assigned to the return value of extend function:
int *a2 = extend( a1, oldSize, newSize );
You can't extend static array.
you can do it like this:
#include <stdio.h>
int *extends(int ar[],int oldsz,int newsz){
int *newAr = malloc(newsz*sizeof(int));
for(int i = 0; i < oldsz;i++){
newAr[i] = ar[i];
}
return newAr;
}
int main(void) {
int i,a[5] = { 1, 2, 3, 4, 5};
int *a1 = extends(a,5,10);
a1[5] = 6;
a1[6] = 7;
a1[7] = 8;
a1[8] = 9;
a1[9] = 10;
a1[10] = 11;
a1[11] = 12;
for(i = 0; i < 12; i++)printf("%d ",a1[i]);
return 0;
}
You can't extend a static array, it's size is determined at compile time.
However, you could declare a1 as a pointer, and use a static initializer to set the initial value,
int *a1 = (int[]){ 1, 2, 5, 4, 1};
then later assign the result of the extend function (which should return an int * like #artm suggested).
I have an integer array that I need to sort containing unix times. I was going to use qsort to sort it which is fairly trivial. However I also have an array of "strings" that needs to remain in the same order as the integer array.
So position 2 in the integer array would correspond with an element in position two of the other array.
Is there anyway using qsort to maintain such a relationship?
Do it like this
#include <stdlib.h>
#include <stdio.h>
struct Data
{
long int time;
const char *string;
};
int
datacmp(const void *const x, const void *const y)
{
return ((struct Data *) x)->time - ((struct Data *) y)->time;
}
int
main(void)
{
struct Data array[] = {
{1234, "1234 Text"},
{1034, "1034 Text"},
{1041, "1041 Text"}
};
size_t count;
count = sizeof(array) / sizeof(array[0]);
for (size_t i = 0 ; i < count ; ++i)
{
fprintf(stderr, "Entry %zu:\n\ttime : %ld\n\tstring: %s\n\n",
i, array[i].time, array[i].string);
}
fprintf(stderr, "\n");
qsort(array, count, sizeof(array[0]), datacmp);
fprintf(stderr, "---- Sorted array:\n");
for (size_t i = 0 ; i < count ; ++i)
{
fprintf(stderr, "Entry %zu:\n\ttime : %ld\n\tstring: %s\n\n",
i, array[i].time, array[i].string);
}
return 0;
}
A more generic solution that actually sorts 2 (or more) arrays, according to one of the arrays, by sorting an array of pointers to the key array, then reordering all of the arrays to sort them (it also restores the array of pointers back to their initial state). The compare function only needs to know the type that the pointers point to. The reorder in place takes O(n) (linear) time as every move places a value in it's final sorted location. In this example, a[] is an array of integers, b[] is an array of pointers to strings (char *).
int compare(const void *pp0, const void *pp1)
{
int i0 = **(int **)pp0;
int i1 = **(int **)pp1;
if(i0 > i1)return -1;
if(i0 < i1)return 1;
return 0;
}
/* ... */
int *pa = malloc(...); /* array of pointers */
int ta; /* temp value for a */
char *tb; /* temp value for b */
/* ... */
/* initialize array of pointers to a[] */
for(i = 0; i < sizeof(a)/sizeof(a[0]); i++)
pa[i] = &a[i];
/* sort array of pointers */
qsort(pa, sizeof(a)/sizeof(a[0]), sizeof(pa[0]), compare);
/* reorder a[] and b[] according to the array of pointers */
for(i = 0; i < sizeof(a)/sizeof(a[0]); i++){
if(i != pa[i]-a){
ta = a[i];
tb = b[i];
k = i;
while(i != (j = pa[k]-a)){
a[k] = a[j];
b[k] = b[j];
pa[k] = &a[k];
k = j;
}
a[k] = ta;
b[k] = tb;
pa[k] = &a[k];
}
}
I have a struct:
struct points{
int i;
int x;
int y;
};
And I made an array of the struct and put elements in it. The i element indicates the label of a certain point. Suppose I have 1 2 3 as an input in the array. 1 corresponds to the label of the point (2, 3). Then I tried to sort the x elements:
for (a=0; a < i; a++){
for (b = 0; b < i; b++){
if (pt[b].x > pt[b+1].x){
temp1 = pt[b].x;
pt[b].x = pt[b+1].x;
pt[b+1].x = temp1;
}
}
}
It was sorted correctly. Now when I printed the i (label), it did not correspond with the x element when sorted. In short, only the x element moved. I want to make the i and y move with the x as it is sorted. What should I do?
Instead of just swapping x you need to swap all the data so that the entire array of structures gets sorted.
You could do this with a separate function, for clarity:
void swap_points(struct points *pa, struct points *pb)
{
const struct points tmp = *pa;
*pa = *pb;
*pb = tmp;
}
Then call that instead of the three inner-most lines of code in your sort.
You really should just use qsort() to do this, it's much simpler:
static int compare_points(const void *va, const void *vb)
{
const struct points *pa = va, *pb = vb;
return pa->i < pb->i ? -1 : pa->i > pb->i;
}
qsort(pt, i, sizeof pt[0], compare_points);
You are actually sorting the array, but only the values for i, not the whole structure!
You'll want to use C's qsort here:
#include <stdlib.h>
#include <stdio.h>
struct points
{
int i;
int x;
int y;
};
int compare(const struct points *a, const struct points *b)
{
if (a->i < b->i) return -1;
if (a->i == b->i) return 0;
if (a->i > b->i) return 1;
}
int main(void)
{
int i;
struct points p[3] = { { 4, 2, 1 }, { 1, 3, 5 }, { 2, 8, 1 } };
qsort(p, 3, sizeof(struct points),
(int (*)(const void*, const void*)) compare);
printf("{ ");
for (i=0; i<3; ++i)
{
printf("{ %d, %d, %d }", p[i].i, p[i].x, p[i].y);
if (i < 2) printf(", ");
}
printf(" }\n");
}
See http://www.cplusplus.com/reference/cstdlib/qsort/
You have to copy the other elements in the struct too.
I suppose you to write a function which replace the values of an element, like this:
void copyPoints(point1* a, point2* b)
{
int temp = a->i;
a->i = b->i;
b->i = temp;
temp = a->x;
a->x = b->x;
b->x = temp;
temp = a->y;
a->y = b->y;
b->y = temp;
}
Then modify the code like this:
for (a=0; a < i; a++)
{
for (b = 0; b < i; b++)
{
if (pt[b].x > pt[b+1].x)
copyPoints(&(pt[b]),&(pt[b+1]));
}
}
I am trying to sort an array of pointers by the memory address:
#include <stdio.h>
#include <stdlib.h>
typedef struct flist {
int size;
struct flist *blink;
struct flist *flink;
} *Flist;
int compare(const void *x, const void *y)
{
Flist a = (Flist)x;
Flist b = (Flist)y;
if(a < b)
return -1;
else
return 1;
}
int main()
{
int a[] = {3, 1, 2, 4, 0};
Flist b[5];
int i;
for(i = 0; i < 5; i++)
b[a[i]] = (Flist)malloc(12);
printf("Here is the array before sorting:\n");
for(i = 0; i < 5; i++)
printf("%p\n", b[i]);
qsort(b, 5, sizeof(Flist), compare);
printf("Here is the array after sorting:\n");
for(i = 0; i < 5; i++)
printf("%p\n", b[i]);
}
However, the program has no effect on the order of the addresses:
Here is the array before sorting:
0x759090
0x759030
0x759050
0x759010
0x759070
Here is the array after sorting:
0x759090
0x759030
0x759050
0x759010
0x759070
Any suggestions would be much appreciated!
You are missing a level of indirection: qsort sends in addresses of elements being sorted, not the elements themselves.
In your case, you are seeing addresses of the addresses of your Flist elements being passed. You need to dereference the pointers passed in after casting to Flist* (which is a pointer to a pointer):
int compare(const void *x, const void *y) {
Flist a = *((Flist*)x);
Flist b = *((Flist*)y);
if(a < b)
return -1;
else
return 1;
}
compare receives the addresses of the array elements. These are of course already in sequence.
To sort by the values, you'd need to change compare to
int compare(const void *x, const void *y)
{
Flist a = *(Flist*)x;
Flist b = *(Flist*)y;
if(a < b)
return -1;
else if (a == b)
return 0;
else
return 1;
}
but since the pointers are not all pointing into the same array (or one past the end), it's technically undefined behaviour.