使用 qsort() 对整数数组进行排序并交换字符串

Using qsort() to sort an array of ints and swap strings

我想按降序对 int *arr 进行排序,同时如果 int *arr 的第二个元素大于 char **words 数组的相应元素第一。我如何使用 qsort()cmpfunc() 来做到这一点?对 ints 进行排序很容易,但是我将如何交换另一个数组中的字符串,因为我没有关于 int 数组的哪两个元素当前排序的索引?

qsort(arr,N,sizeof(int),cmpfunc);

``

int cmpfunc(const void * a, const void * b) {
    int val1 = *(int *)a;
    int val2 = *(int *)b;

    if(val2 > val1) {
        /* swap string positions */
        return 1;
    } else if(val2 < val1) {
        return -1;
    } else {
        return 0;
    }
}

有几种方法可以解决这个问题。首先,直接回答你的问题:

  1. 创建一个 size_t 的新数组,包含值 0 .. N.
  2. 运行 qsort 在那个数组上,而不是
int val1 = *(int *)a;
int val2 = *(int *)b;

你会

int val1 = arr[*(int *)a];
int val2 = arr[*(int *)b];

然后照常比较。

  1. 现在你有一个 indices 的数组 arr (一个排列),其顺序将使 arr 有序。现在我们可以应用那个排列到arrwords。一种选择是只要您想按排序顺序访问两个数组,就简单地遍历索引数组。另一种是复制两个数组,然后根据排列将元素复制回去。

其次:你也可以用struct { int * ; char ** }的数组做同样的事情(每个指向arr的一个成员和words的对应成员),对这个进行排序array by its int member 同时将原始数组留在原处,并从那里开始使用它。

第三:您可以放弃并行阵列。如果数据如此紧密相关,那么为什么它在两个不相关的变量中?如果一开始就将这两种数据放在一个结构中,那么您可以对结构数组进行排序,然后对这些结构做任何您想做的事情,而不用担心相关性会不同步。

您可以使用 qsort_r()(如果可用,它是 GNU 扩展。在 Microsoft 环境中它被称为 qsort_s(),但在其他方面具有相同的语义)将另一个参数传递给比较函数,例如结构中的基本数组指针 int *arrchar **words

struct cmpargs {
    int *arr;
    char **words;
} args;

...

args.arr = arr;
args.words = words;

qsort_r(arr,N,sizeof(int),cmpfunc, &args);

并且在您的比较功能中,您现在可以访问这些并可以使用它们进行交换:

int cmpfunc(const void * a, const void * b, void *_args) {
    struct cmpargs args = _args;

    int *a1 = a;
    int *a2 = b;

    int idx1 = a - args->arr;
    int idx2 = b - args->arr;

现在您可以在比较函数中交换相应数组 args->word 中的元素,如果它 return 1.

I want to sort an int *arr in descending order and at the same time swap the corresponding elements of a char **words array if the second element of the int *arr is greater than the first one. How can i do this using qsort() and the cmpfunc() ?

没有干净的方法来完成这项工作,因为它需要 qsort() 没有传达给比较函数的上下文信息:arr 和 [=17 的基地址=] 数组。事实上,后者甚至没有首先传达给 qsort() 本身。

在支持 C11 线程的实现中,一个可行的替代方法是将这些指针存储在 thread-specific storage 中,然后让比较函数从那里检索它们。然后,您可以计算被比较元素的索引作为它们与基指针之间的指针差异,并且可以使用其基指针和您获得的索引执行 words 的正常交换。

但这可能不是您真正想要的!我推断您正在尝试对 words 的元素进行与您所做的相同的排列arr 的元素。您所描述的内容绝不能肯定会产生这种结果,因为您根本无法确定 qsort() 每次比较结果以某种方式进行时都会执行交换。

如果确实两个数组必须分开,正确的方法是准备和排序某种辅助数组。在该区域中有多种选择,可以让您重新排序一个或两个主阵列,或者像您已经完成的那样访问它们。例如,您可以准备一个 int (*perm)[2],每个元素(int[2])包含 arr 的对应元素和该元素的初始索引。然后,您可以根据需要对该数组数组进行排序,并直接得出排列。然后,您可以重新排序 arrwords 以匹配,或者通过排列 (words[perm[k][1]]).

间接访问它们

但您也可以考虑编写自己的专用排序函数,而不是使用qsort()。这样的函数可以将指向两个数组的基指针作为参数——正确输入,甚至——然后直接执行你需要的协同排序。