C语言中用qsort对多维数组按指定列排序的实现方法
按指定列索引排序二维数组的实现方案
问题背景
原实现代码如下:
#include<stdio.h> #include<stdlib.h> int comp(const void *a, const void *b) { return (((int*)a)[0] - ((int*)b)[0]); } int main() { int arr[][4] = { {4,0,5,2}, {0,5,4,6}, {4,5,6,6} }; int ROWS = sizeof(arr)/sizeof(arr[0]); qsort(arr, ROWS, sizeof(arr[0]), comp); for(int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++){ for(int j = 0; j < sizeof(arr[0])/sizeof(arr[0][0]); j++){ printf("%d ", arr[i][j]); } printf("\n"); } }
需求是根据用户指定的列索引对二维数组行排序,预期效果如下:
column index = 0 0 5 4 6 4 0 5 2 4 5 6 6 column index = 1 4 0 5 2 0 5 4 6 4 5 6 6 column index = 2 0 5 4 6 4 0 5 2 4 5 6 6 column index = 3 4 0 5 2 0 5 4 6 4 5 6 6
疑问:是否需要为每个列索引写不同的比较器?能否动态传递排序索引给比较器?
解决方案
不需要写多个比较器,有两种实用方法实现动态传递列索引:
方法1:使用全局变量传递列索引
这是最直接的方案,通过全局变量让比较器函数获取当前要排序的列索引:
修改后的完整代码:
#include<stdio.h> #include<stdlib.h> // 全局变量存储要排序的列索引 int sort_column; int comp(const void *a, const void *b) { // 用全局变量指定的列进行比较 return ((*(int**)a)[sort_column] - (*(int**)b)[sort_column]); } int main() { int arr[][4] = { {4,0,5,2}, {0,5,4,6}, {4,5,6,6} }; int ROWS = sizeof(arr)/sizeof(arr[0]); int COLS = sizeof(arr[0])/sizeof(arr[0][0]); // 示例:测试列索引0-3的排序效果 for (sort_column = 0; sort_column < COLS; sort_column++) { printf("column index = %d\n", sort_column); // 每次排序前复制原数组,避免前一次排序影响结果 int temp_arr[ROWS][COLS]; for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { temp_arr[i][j] = arr[i][j]; } } qsort(temp_arr, ROWS, sizeof(temp_arr[0]), comp); // 打印排序结果 for(int i = 0; i < ROWS; i++){ for(int j = 0; j < COLS; j++){ printf("%d ", temp_arr[i][j]); } printf("\n"); } printf("\n"); } return 0; }
注意:全局变量的弊端是不适合多线程场景,单线程程序使用足够简单高效。
方法2:使用qsort_r(GNU扩展)实现上下文传递
如果编译器支持GNU扩展(比如GCC、MinGW),可以用qsort_r替代qsort,它允许直接传递上下文参数给比较器,无需全局变量,更健壮:
完整代码示例:
#include<stdio.h> #include<stdlib.h> // 比较器函数,额外接收上下文参数(列索引) int comp_r(const void *a, const void *b, void *arg) { int col = *(int*)arg; return ((*(int**)a)[col] - (*(int**)b)[col]); } int main() { int arr[][4] = { {4,0,5,2}, {0,5,4,6}, {4,5,6,6} }; int ROWS = sizeof(arr)/sizeof(arr[0]); int COLS = sizeof(arr[0])/sizeof(arr[0][0]); for (int col = 0; col < COLS; col++) { printf("column index = %d\n", col); int temp_arr[ROWS][COLS]; for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { temp_arr[i][j] = arr[i][j]; } } // 调用qsort_r,把列索引作为上下文参数传递 qsort_r(temp_arr, ROWS, sizeof(temp_arr[0]), comp_r, &col); // 打印结果 for(int i = 0; i < ROWS; i++){ for(int j = 0; j < COLS; j++){ printf("%d ", temp_arr[i][j]); } printf("\n"); } printf("\n"); } return 0; }
关键说明
- 两种方法都实现了动态指定排序列,无需为每个列写单独的比较器。
- 代码中加入临时数组复制,是为了每次排序都基于原始数组,避免前一次排序结果干扰后续测试。
- 若数组元素可能为大数,比较器中的减法可能溢出,建议改用
if-else判断返回值,更安全:int val_a = ((*(int**)a)[col]); int val_b = ((*(int**)b)[col]); if (val_a > val_b) return 1; else if (val_a < val_b) return -1; else return 0;
内容的提问来源于stack exchange,提问作者Bittu970
相关产品推荐
相关产品推荐

