使用 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;
}
}
有几种方法可以解决这个问题。首先,直接回答你的问题:
- 创建一个
size_t
的新数组,包含值 0 .. N
.
- 运行
qsort
在那个数组上,而不是
int val1 = *(int *)a;
int val2 = *(int *)b;
你会
int val1 = arr[*(int *)a];
int val2 = arr[*(int *)b];
然后照常比较。
- 现在你有一个 indices 的数组
arr
(一个排列),其顺序将使 arr
有序。现在我们可以应用那个排列到arr
和words
。一种选择是只要您想按排序顺序访问两个数组,就简单地遍历索引数组。另一种是复制两个数组,然后根据排列将元素复制回去。
其次:你也可以用struct { int * ; char ** }
的数组做同样的事情(每个指向arr
的一个成员和words
的对应成员),对这个进行排序array by its int member 同时将原始数组留在原处,并从那里开始使用它。
第三:您可以放弃并行阵列。如果数据如此紧密相关,那么为什么它在两个不相关的变量中?如果一开始就将这两种数据放在一个结构中,那么您可以对结构数组进行排序,然后对这些结构做任何您想做的事情,而不用担心相关性会不同步。
您可以使用 qsort_r()
(如果可用,它是 GNU 扩展。在 Microsoft 环境中它被称为 qsort_s()
,但在其他方面具有相同的语义)将另一个参数传递给比较函数,例如结构中的基本数组指针 int *arr
和 char **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
的对应元素和该元素的初始索引。然后,您可以根据需要对该数组数组进行排序,并直接得出排列。然后,您可以重新排序 arr
和 words
以匹配,或者通过排列 (words[perm[k][1]]
).
间接访问它们
但您也可以考虑编写自己的专用排序函数,而不是使用qsort()
。这样的函数可以将指向两个数组的基指针作为参数——正确输入,甚至——然后直接执行你需要的协同排序。
我想按降序对 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;
}
}
有几种方法可以解决这个问题。首先,直接回答你的问题:
- 创建一个
size_t
的新数组,包含值 0 ..N
. - 运行
qsort
在那个数组上,而不是
int val1 = *(int *)a;
int val2 = *(int *)b;
你会
int val1 = arr[*(int *)a];
int val2 = arr[*(int *)b];
然后照常比较。
- 现在你有一个 indices 的数组
arr
(一个排列),其顺序将使arr
有序。现在我们可以应用那个排列到arr
和words
。一种选择是只要您想按排序顺序访问两个数组,就简单地遍历索引数组。另一种是复制两个数组,然后根据排列将元素复制回去。
其次:你也可以用struct { int * ; char ** }
的数组做同样的事情(每个指向arr
的一个成员和words
的对应成员),对这个进行排序array by its int member 同时将原始数组留在原处,并从那里开始使用它。
第三:您可以放弃并行阵列。如果数据如此紧密相关,那么为什么它在两个不相关的变量中?如果一开始就将这两种数据放在一个结构中,那么您可以对结构数组进行排序,然后对这些结构做任何您想做的事情,而不用担心相关性会不同步。
您可以使用 qsort_r()
(如果可用,它是 GNU 扩展。在 Microsoft 环境中它被称为 qsort_s()
,但在其他方面具有相同的语义)将另一个参数传递给比较函数,例如结构中的基本数组指针 int *arr
和 char **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 achar **words
array if the second element of the int*arr
is greater than the first one. How can i do this usingqsort()
and thecmpfunc()
?
没有干净的方法来完成这项工作,因为它需要 qsort()
没有传达给比较函数的上下文信息:arr
和 [=17 的基地址=] 数组。事实上,后者甚至没有首先传达给 qsort()
本身。
在支持 C11 线程的实现中,一个可行的替代方法是将这些指针存储在 thread-specific storage 中,然后让比较函数从那里检索它们。然后,您可以计算被比较元素的索引作为它们与基指针之间的指针差异,并且可以使用其基指针和您获得的索引执行 words
的正常交换。
但这可能不是您真正想要的!我推断您正在尝试对 words
的元素进行与您所做的相同的排列arr
的元素。您所描述的内容绝不能肯定会产生这种结果,因为您根本无法确定 qsort()
每次比较结果以某种方式进行时都会执行交换。
如果确实两个数组必须分开,正确的方法是准备和排序某种辅助数组。在该区域中有多种选择,可以让您重新排序一个或两个主阵列,或者像您已经完成的那样访问它们。例如,您可以准备一个 int (*perm)[2]
,每个元素(int[2]
)包含 arr
的对应元素和该元素的初始索引。然后,您可以根据需要对该数组数组进行排序,并直接得出排列。然后,您可以重新排序 arr
和 words
以匹配,或者通过排列 (words[perm[k][1]]
).
但您也可以考虑编写自己的专用排序函数,而不是使用qsort()
。这样的函数可以将指向两个数组的基指针作为参数——正确输入,甚至——然后直接执行你需要的协同排序。