Home > Software design >  Sorting an array virtually, and storing the order only
Sorting an array virtually, and storing the order only

Time:01-21

I've got this code, but it isn't working as should. I need to virtually sort 'val' array in descending order, and store the order in 'order' array.

#include <stdio.h>
#define NUM_J_DIRS 4
#define FRAC_LEFT 0
#define FRAC_RIGHT 1
#define FRAC_FORWARD 2
#define FRAC_BACK 3
#define FIRST 0
#define SECOND 1
#define THIRD 2
#define FOURTH 3

struct iv
{
  int index;
  float value;
};

struct Fractions
{
  int order[NUM_J_DIRS];    //this is where we store order of 'val'
  float val[NUM_J_DIRS];    //once declared, this don't change
  int enabled[NUM_J_DIRS];  //once declared, this don't change
};

int main ()
{
  struct Fractions fractions;   
  struct iv iv[NUM_J_DIRS];
  fractions.val[FRAC_LEFT] = 0.1;
  fractions.val[FRAC_RIGHT] = 1.0;
  fractions.val[FRAC_FORWARD] = 1.0;
  fractions.val[FRAC_BACK] = 0.5;

  // populate iv from val 
  for (int i = 0; i < NUM_J_DIRS; i  )
  {
    iv[i].index = i;
    iv[i].value = fractions.val[i];
  }

  // sort kv by value 
  for (int i = 0; i < NUM_J_DIRS; i  )
  {
    for (int j = i   1; j < NUM_J_DIRS; j  )
    {
      if (iv[i].value < iv[j].value)
      {
        struct iv temp = iv[i];
        iv[i] = iv[j];
        iv[j] = temp;
      }
    }
  }

  // set order 
  for (int i = 0; i < NUM_J_DIRS; i  )
  {
    fractions.order[iv[i].index] = i;
  }

  printf("order = %i, dir: %i, the value was: %f\n",
      FIRST, fractions.order[FIRST], fractions.val[fractions.order[FIRST]]);
  printf("order = %i, dir: %i, the value was: %f\n", 
      SECOND, fractions.order[SECOND], fractions.val[fractions.order[SECOND]]);
  printf("order = %i, dir: %i, the value was: %f\n", 
      THIRD, fractions.order[THIRD], fractions.val[fractions.order[THIRD]]);
  printf("order = %i, dir: %i, the value was: %f\n", 
      FOURTH, fractions.order[FOURTH], fractions.val[fractions.order[FOURTH]]);
  return 0;
}

outputs: ​

order = 0, dir: 3, the value was: 0.500000
order = 1, dir: 0, the value was: 0.100000
order = 2, dir: 1, the value was: 1.000000
order = 3, dir: 2, the value was: 1.000000

But should output: ​

order = 0, dir: 1, the value was: 1.000000
order = 1, dir: 2, the value was: 1.000000
order = 2, dir: 3, the value was: 0.500000
order = 3, dir: 0, the value was: 0.100000

​ The order between dir 1 and dir 2 is interchangeable since they have the same value. The order of direction of the same values is not important.

Code above should work imo, but doesn't. I have spent countless time figuring out why not.

CodePudding user response:

After sorting iv, the elements are in descending order by value, and each one carries a corresponding index into the fractions.val array. So iv[0].index gives the index of the greatest element, iv[1].index gives the index of the next greatest, etc. Therefore, when you read that out, you want the first element of order to take the index from the first element of iv, the second from the second, and so on. But that's not what this says:

  // set order 
  for (int i = 0; i < NUM_J_DIRS; i  )
  {
    fractions.order[iv[i].index] = i;
  }

You have reversed the sense of i and iv[i].index. What you actually want is

  for (int i = 0; i < NUM_J_DIRS; i  ) 
  {
    fractions.order[i] = iv[i].index;
  }

After I make that change, your program's output prints the values in descending order for me.

CodePudding user response:

Declare this as your compare function:

int compareFunction(const void *p1, const void *p2, void *arg) {
    struct Fractions* f = (struct Fractions*)arg;
    int index1 = *(int*)p1;
    int index2 = *(int*)p2;
    if (f->val[index1] < f->val[index2]) {
        return 1;
    }
    if (f->val[index1] > f->val[index2]) {
        return -1;
    }
    return 0;
}

Then to sort the "order" array based on the existing order of the "val" array:

for (int i = 0; i < NUM_J_DIRS; i  ) {
    fractions.order[i] = i;    
}
qsort_r(fractions.order, NUM_J_DIRS, sizeof(int), &fractions);

You get qsort_r by adding a #include <stdlib.h> to the top of your source file.

  • Related