【问题标题】:Sorting a C array based on contents of another array根据另一个数组的内容对 C 数组进行排序
【发布时间】:2011-05-20 19:27:39
【问题描述】:

我正在尝试对其元素为索引的数组A 进行排序。索引引用另一个数组B,其值将确定A 的顺序。所以,我想对A 进行排序,使B[ A[i] ] 增加。

例如:

A = [0, 1, 4, 5, 7] B = [5, 3, 8, 2, 2, 7, 1, 6, 3, 9]

排序A 将是

A' = [ 7, 4, 1, 0, 5 ]

这可以通过 C 的内置排序实现吗,还是我必须编写自己的实现?

编辑:这些数组是局部函数变量。

【问题讨论】:

  • 会有一些丑陋的黑客可以让它与 qsort 一起工作,但我认为你最好编写自己的版本..
  • @Pavan 我更喜欢在沙漠中与僵尸作战,而不是在生产中使用我自己的分类程序。
  • 这不是一个丑陋的黑客。只是有一个函数将数组值映射到排序顺序。在这种情况下,该函数可以通过数组查找来实现,但这并不是一个不寻常的要求。

标签: c arrays sorting


【解决方案1】:

如果你想使用qsort,最好的办法是将A中的索引和B中的值重新包装到一个结构中,然后基于该结构的新数组进行比较器。例如:

typedef struct
{
    int index_from_A;
    int value_from_B;
} index_value_wrapper;

index_value_wrapper index_wrapper_array[5];

for (int i=0; i < 5; i++)
{
    index_wrapper_array[i].index_from_A = A[i];
    index_wrapper_array[i].value_from_B = B[A[i]];
}

int comparitor (const void* lhs, const void* rhs)
{
    return (lhs.value_from_B - rhs.value_from_B);
}

现在您可以在 struct 数组上运行 qsort,然后从那里您可以提取原始数组 A 所需的正确排序序列,而无需使用自定义排序函数。

【讨论】:

    【解决方案2】:

    如果你有它,qsort_r 提供了一种方法来做到这一点。您可以在附加参数中为其提供上下文信息。该上下文被传递给比较函数。您可以访问该附加信息以提取所需的排序信息。

    微软编译器也有类似的:qsort_s

    【讨论】:

      【解决方案3】:

      我认为您可以使用 qsort 和自定义比较器

      int comparator(const void *x, const void *y)
      {
          return ( b[*(int*)x] - b[*(int*)y] );
      }
      

      【讨论】:

      • 有没有办法将数组引用传递给比较器?
      • @ajwood 我不确定我是否理解你的问题
      • Ajwood,如果你指的是数组索引,不,数组元素会随着排序的进行而移动
      • @cnicutar:你的答案会很完美...... 但是这些数组是函数中的局部变量,所以比较器无法检查B的值跨度>
      • @ajwood:据我所知,在上面的代码中,b 必须是某种类型的全局可访问数组。
      【解决方案4】:

      创建另一个struct { int a_value; int b_value} 类型的数组C,将每个元素初始化为a 的每个索引的值,并从b 中查找该值。排序,遍历排序后的 C 将 a_values 复制回 A。

      维奥拉。不,那是一把大小提琴。瞧!

      【讨论】:

        【解决方案5】:

        使用您的规则作为 qsort 的比较函数(只要 B 比 A 长):

        #include <stdio.h>
        #include <stdlib.h>
        
        int A[] = {0, 1, 4, 5, 7};
        int B[]= {5, 3, 8, 2, 2, 7, 1, 6, 3, 9};
        
         int my_cmp(const void *a_, const void *b_,void *arg_)
         {
           const int *a = a_, *b = b_;
        
           if(B[*a] == B[*b])
               return 0;
            else if (B[*a] < B[*b])
                return -1;
            else
                return 1;
        
        }
        
        int main(int argc,char *arga[])
        {
            int i;
        
            qsort(A,sizeof A/sizeof A[0] ,sizeof A[0],my_cmp);
        
            puts("Sorted A");
            for(i = 0 ; i < sizeof A/sizeof A[0]; i++) {
                printf("A[%d] : %d B[A[%d]] : %d\n",i,A[i],i,B[A[i]]);
            }
        
            return 0;
        }
        

        这给出了:

        $ ./a.out
        Sorted A
        A[0] : 4 B[A[0]] : 2
        A[1] : 1 B[A[1]] : 3
        A[2] : 0 B[A[2]] : 5
        A[3] : 7 B[A[3]] : 6
        A[4] : 5 B[A[4]] : 7
        

        在许多平台上也可以使用 qsort_r(在 linux 上,您必须先 #define _GNU_SOURCE 才能使用它,然后再包含 &lt;stdlib.h&gt; 。使用它,您可以将比较函数更改为例如

        int my_cmp(const void *a_, const void *b_,void *arg_)
         {
            const int *a = a_, *b = b_, *arg = arg_;
        
           if(arg[*a] == arg[*b])
               return 0;
            else if (arg[*a] < arg[*b])
                return -1;
            else
                return 1;
        
        }
        

        并像调用 qsort_r 一样

        qsort_r(A,sizeof A/sizeof A[0] ,sizeof A[0],my_cmp,B);
        

        【讨论】:

        • 只要不是多线程的,它就可以很好地工作。如果它不是单线程的并且参考数据(B)不是静态的,那么它就不会工作。
        • @Paul qsort 是 C 中唯一的标准排序函数,它的工作原理就是这样,否则你将不得不自己动手,或者使用非标准的东西,比如 qsort_r - 为此添加了一个示例.除非您在多线程环境中,否则 A 和 B 很可能是本地的。您只需要在调用 qsort 之前为您的 B 数组设置一个全局 int *
        • @nos,标准与否,如果它不起作用,你就不能使用它:) 全局工作(虽然它有点代码味道)或使用包装结构作为其他结构(包括我)建议。
        • @Nos,是的,确实如此。但是当我添加我的评论时,它不是你的答案或评论的一部分......如果它可用,qsort_r 绝对是要走的路
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-12-18
        • 2011-05-02
        相关资源
        最近更新 更多