【问题标题】:Sort an array in the relative order of elements of another array in c按照c中另一个数组的元素的相对顺序对数组进行排序
【发布时间】:2019-11-03 23:04:09
【问题描述】:

我希望按照第一个数组对第二个数组进行排序。例如

first = {1,8,7,2,4}
second = {9,7,2,10,3}

我希望第一个保持不变,第二个按照与第一个相同的相对顺序进行排序。即最低值在索引 0 处,第二低值在索引 3 处,第三低值在索引 4 处等等

second = {2,10,9,3,7}

我已经尝试了以下代码

#include <stdio.h>

typedef struct
{
    int num;
    int pos;
}ArrType;

ArrType arrA[5] = {{1,0},{8,1},{7,2},{2,3},{4,4}};
ArrType arrB[5] = {{9,0},{7,1},{2,2},{10,3},{3,4}};;

int cmparr(const void *a, const void *b)
{
    ArrType *tmpa, *tmpb;
    tmpa = (ArrType*) a;
    tmpb = (ArrType*) b;

    return(arrA[tmpa->pos].num - arrA[tmpb->pos].num);
}
int main(void)
{
    int i;
    qsort(arrB,5, sizeof(ArrType), cmparr);

    for (i=0; i<5; i++)
    {
        printf ("%d ",arrB[i].num);
    }
    return (0);
}

实际输出是

9 10 3 2 7

我对不同的数据结构持开放态度,但arrB 应该只排序一次。

我在 C++、Javascipt 和其他语言中看到了一些解决方案。但是在 C 中没有解决方案。

编辑 - 这些数组在最终程序中会非常大。我正在寻找一个单一的排序操作。即单个呼叫qsort

【问题讨论】:

  • 实际输出不如预期。 cmparr 函数或使用的数据结构有问题。
  • @Socowi - 我已经指定了预期的输出second = {2,10,9,3,7}
  • @Socowi 我相信它更像是:您检查first 的顺序,所以最低的是位置0,接下来是位置3,依此类推。然后您将此顺序应用于second,以便您搜索最低值并将其放置在位置 0 然后您搜索下一个值并将其放置在位置 3 等等。
  • @Socowi 对不起,现在我理解你的评论,你说得对
  • @Ranon 您不会通过单个排序操作找到解决方案。由于您隐含地需要能够回答“数组中最大的元素是什么元素?”这个问题。您要么需要对它们都进行排序,要么搜索它们——对未排序数组进行更昂贵的操作。

标签: c arrays algorithm sorting


【解决方案1】:

这是我的方法,它使用了两次 qsort 并且 arrC 包含结果。

#include <stdio.h>

typedef struct
{   
    int num;
    int pos;
}ArrType;

ArrType arrA[5] = {{1,0},{8,1},{7,2},{2,3},{4,4}};
int arrB[5] = {9,7,2,10,3};;
int arrC[5];
int cmpInt(const void *a, const void *b)
{   
        return(*a - *b);
}
int cmp(const void *a, const void *b)
{   
    ArrType *tmpa, *tmpb;
    tmpa = (ArrType*) a;
    tmpb = (ArrType*) b; 
        return(tmpa->num - tmpb->num);
}
int main(void)
{
    int i;
    qsort(arrA,5, sizeof(ArrType), cmp);
    qsort(arrB,5, sizeof(ArrType), cmpInt);
    for (i=0; i<5; i++)
    {   
        arrC[arrA[i].pos] = arrB[i];
    }   
    return (0);
}

【讨论】:

  • 这里有2个排序操作。可以只用一次排序操作完成吗?
  • @Ranon 我们需要找到排序与给定顺序的映射,这将需要一个排序过程。其他排序过程用于对第二个数组进行排序,以便使用映射是线性操作。这是一个 NlogN 解决方案,如果我们设法在单个排序操作中完成它,它仍然是 NlogN。
【解决方案2】:

由于 C 没有 lambda 比较(可用于根据 first[] 对索引数组进行排序),下面的代码使用 qsort 将指针数组 ap[] 排序到 first[] 的元素()。使用指针消除了将数组名称作为参数传递给比较函数的需要,这反过来又允许比较函数与 qsort() 一起工作。表达式 (ap[i]-first) 将指针转换为索引。 Next second[] 被排序,同样使用 qsort()。然后将 ap[] 用作一组秩,以在 O(n) 时间内对 second[] 进行重新排序。

解释按等级重新排序与按索引重新排序:

    dst[rank[i]] = src[i];              /* reorder by rank */
    dst[i] = src[index[i]];             /* reorder by index */

示例代码:

#include <memory.h>
#include <stdio.h>
#include <stdlib.h>

/* compare for ptr to integer */
int cmppi(const void *p0, const void *p1){
    return (*(int *)p0 - *(int *)p1);
}

/* compare for ptr to ptr to integer */
int cmpppi(const void *p0, const void *p1){
    return (**(int **)p0 - **(int **)p1);
}

int main()
{
int first[] =  {1, 8, 7, 2, 4};
int second[] = {9, 7, 2,10, 3};
int **ap;                               /* array of pointers */
int *tmpp;
int tmpi;
size_t i, j;

    /* allocate and generate array of pointers to first[] */
    ap = (int **)malloc(sizeof(first)/sizeof(first[0])*sizeof(int *));
    for(i = 0; i < sizeof(first)/sizeof(first[0]); i++)
        ap[i] = &first[i];
    /* sort ap  */
    qsort(ap, sizeof(first)/sizeof(first[0]), sizeof(int *), cmpppi);
    /* sort second */
    qsort(second, sizeof(second)/sizeof(second[0]), sizeof(int), cmppi);
    /* reorder ap and second in place using ap as rank (O(n) time) */
    for (i = 0; i < sizeof(second) / sizeof(second[0]); i++){
        while(i != (j = ap[i] - first)){
            tmpp = ap[i];               /* swap(ap[i], ap[j]) */
            ap[i] = ap[j];
            ap[j] = tmpp;
            tmpi = second[i];           /* swap(second[i], second[j] */
            second[i] = second[j];
            second[j] = tmpi;
        }
    }   
    /* display second[] */
    for (i = 0; i < sizeof(second) / sizeof(second[0]); i++)
        printf("%3d", second[i]);
    printf("\n");
    free(ap);
    return 0;
}

【讨论】:

    【解决方案3】:

    您需要创建与所需排序匹配的元数据(即索引数组)。然后将该元数据应用到第二个数组。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int first[] = {1,8,7,2,4};
    int second[] = {9,7,2,10,3};
    
    int compare(const void * a, const void * b);
    int binary_search(int array[], int min, int max, int target);
    void print_array(int * array, int c);
    
    int main()
    {
      int idx;
      int c = sizeof(first)/sizeof(int);
      int * sorted = NULL;
      int * indexes = NULL;
      int * result = NULL;
    
      if (NULL == (sorted = malloc(sizeof(first)))) {
          return -1;
      }
      memcpy(sorted, first, sizeof(first));
    
      if (NULL == (indexes = malloc(sizeof(first)))) {
          free(sorted);
          return -1;
      }
      memset(indexes, -1, sizeof(first));
    
      if (NULL == (result = malloc(sizeof(second)))) {
          free(sorted);
          free(indexes);
          return -1;
      }
      memset(result, -1, sizeof(second));
    
      // 1st: Sort the reference array
      qsort (sorted, c, sizeof(int), compare);
    
      // 2nd: Record the position of each sorted element in the original array (this is your meta-data)
      for (idx=0; idx<c; idx++) {
          indexes[idx] = binary_search(sorted, 0, c, first[idx]);
      }
    
      // 3rd sort the target array
      memcpy(sorted, second, sizeof(second));
      qsort (sorted, c, sizeof(int), compare);
    
      // 4th apply the stored positions to the sorted target array
      for (idx = 0; idx < c; idx++) {
          result[idx] = sorted[indexes[idx]];
      }
      print_array(result, c);
    
      free(result);
      free(indexes);
      free(sorted);
      return 0;
    }
    
    int compare(const void * a, const void * b)
    {
      return ( *(int*)a - *(int*)b );
    }
    
    int binary_search(int array[], int min, int max, int target)
    {
        int mid;
        while (min <= max)
        {
            mid = min + (max - min)/2;
            if (target > array[mid])
                min = mid + 1;
            else if (target < array[mid])
                max = mid - 1;
            else
                return mid;
        }
        return -1;
    }
    
    void print_array(int * array, int c)
    {
        for(int i = 0; i < c; i++) {
            printf("%d ", array[i]);
        } 
        printf("\n");
    }
    

    Demo

    【讨论】:

    • 本方案有3种排序操作。由于数组的大小会很大,我正在寻找一个单一的排序操作。
    • 第三个在哪里?没关系,2 大于 1。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    • 1970-01-01
    • 1970-01-01
    • 2019-09-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多