您链接到 (C library function to do sort) 的问题一般显示了如何使用称为 qsort() 的标准 C 库函数,但您的要求不是常见问题之一。为了能够对oo 数组进行排序,比较器函数必须能够访问x 数组以及从qsort() 本身传递给它的数据。
此代码以合理的经济性实现了这一目标:
#include <stdio.h>
#include <stdlib.h>
typedef double VecType;
#define PRIf_VecType "f"
static VecType *base;
static int compare(const void *p1, const void *p2)
{
const int i1 = *(int *)p1;
const int i2 = *(int *)p2;
if (base[i1] < base[i2])
return -1;
else if (base[i1] > base[i2])
return +1;
else
return 0;
}
static void print_arrays(const char *tag, size_t x_size, VecType *x, int *oo)
{
printf("%s:\n", tag);
for (size_t i = 0; i < x_size; i++)
printf("%zu: oo[%zu] = %d, x[oo[%zu]] = %4.2" PRIf_VecType
", x[%zu] = %4.2" PRIf_VecType "\n",
i, i, oo[i], i, x[oo[i]], i, x[i]);
}
int main(void)
{
VecType x[] = { 3.45, 1.23, 9.14, 4.67, 2.19, 3.45, 5.92 };
size_t x_size = sizeof(x) / sizeof(x[0]);
int oo[x_size];
for (size_t i = 0; i < x_size; i++)
oo[i] = (int)i;
print_arrays("Before", x_size, x, oo);
base = x;
qsort(oo, x_size, sizeof(oo[0]), compare);
print_arrays("After", x_size, x, oo);
return 0;
}
样本输出:
Before:
0: oo[0] = 0, x[oo[0]] = 3.45, x[0] = 3.45
1: oo[1] = 1, x[oo[1]] = 1.23, x[1] = 1.23
2: oo[2] = 2, x[oo[2]] = 9.14, x[2] = 9.14
3: oo[3] = 3, x[oo[3]] = 4.67, x[3] = 4.67
4: oo[4] = 4, x[oo[4]] = 2.19, x[4] = 2.19
5: oo[5] = 5, x[oo[5]] = 3.45, x[5] = 3.45
6: oo[6] = 6, x[oo[6]] = 5.92, x[6] = 5.92
After:
0: oo[0] = 1, x[oo[0]] = 1.23, x[0] = 3.45
1: oo[1] = 4, x[oo[1]] = 2.19, x[1] = 1.23
2: oo[2] = 5, x[oo[2]] = 3.45, x[2] = 9.14
3: oo[3] = 0, x[oo[3]] = 3.45, x[3] = 4.67
4: oo[4] = 3, x[oo[4]] = 4.67, x[4] = 2.19
5: oo[5] = 6, x[oo[5]] = 5.92, x[5] = 3.45
6: oo[6] = 2, x[oo[6]] = 9.14, x[6] = 5.92
'after' 的打印向我们保证数组 x 没有改变,但数组 oo 已更新,因此 x[oo[i]] 位于 ith 位置排序顺序。
BSD(因此也包括 Mac OS X)提供了 qsort() 的非标准替代方案,即 qsort_r():
void qsort_r(void *base, size_t nel, size_t width, void *thunk,
int (*compar)(void *, const void *, const void *));
qsort_r() 函数的行为与qsort() 相同,不同之处在于它需要一个附加参数thunk,它作为第一个参数原样传递给指向compar 的函数。这允许比较函数在不使用全局变量的情况下访问其他数据,因此qsort_r() 适用于必须可重入的函数。
根据qsort_r() 编写代码是一组相当微不足道的更改:
#include <stdio.h>
#include <stdlib.h>
typedef double VecType;
#define PRIf_VecType "f"
static int compare(void *thunk, const void *p1, const void *p2)
{
const VecType *base = (VecType *)thunk;
const int i1 = *(int *)p1;
const int i2 = *(int *)p2;
if (base[i1] < base[i2])
return -1;
else if (base[i1] > base[i2])
return +1;
else
return 0;
}
static void print_arrays(const char *tag, size_t x_size, VecType *x, int *oo)
{
printf("%s:\n", tag);
for (size_t i = 0; i < x_size; i++)
printf("%zu: oo[%zu] = %d, x[oo[%zu]] = %4.2" PRIf_VecType
", x[%zu] = %4.2" PRIf_VecType "\n",
i, i, oo[i], i, x[oo[i]], i, x[i]);
}
int main(void)
{
VecType x[] = { 3.45, 1.23, 9.14, 4.67, 2.19, 3.45, 5.92 };
size_t x_size = sizeof(x) / sizeof(x[0]);
int oo[x_size];
for (size_t i = 0; i < x_size; i++)
oo[i] = (int)i;
print_arrays("Before", x_size, x, oo);
qsort_r(oo, x_size, sizeof(oo[0]), x, compare);
print_arrays("After", x_size, x, oo);
return 0;
}
这样的示例输出(与其他代码的输出相同):
Before:
0: oo[0] = 0, x[oo[0]] = 3.45, x[0] = 3.45
1: oo[1] = 1, x[oo[1]] = 1.23, x[1] = 1.23
2: oo[2] = 2, x[oo[2]] = 9.14, x[2] = 9.14
3: oo[3] = 3, x[oo[3]] = 4.67, x[3] = 4.67
4: oo[4] = 4, x[oo[4]] = 2.19, x[4] = 2.19
5: oo[5] = 5, x[oo[5]] = 3.45, x[5] = 3.45
6: oo[6] = 6, x[oo[6]] = 5.92, x[6] = 5.92
After:
0: oo[0] = 1, x[oo[0]] = 1.23, x[0] = 3.45
1: oo[1] = 4, x[oo[1]] = 2.19, x[1] = 1.23
2: oo[2] = 5, x[oo[2]] = 3.45, x[2] = 9.14
3: oo[3] = 0, x[oo[3]] = 3.45, x[3] = 4.67
4: oo[4] = 3, x[oo[4]] = 4.67, x[4] = 2.19
5: oo[5] = 6, x[oo[5]] = 5.92, x[5] = 3.45
6: oo[6] = 2, x[oo[6]] = 9.14, x[6] = 5.92