【问题标题】:How to write a comparator function for qsort for a 2D array?如何为二维数组编写 qsort 的比较器函数?
【发布时间】:2018-10-09 14:22:45
【问题描述】:

我有一个 n*2 大小的数组。我想根据它们在第二列的值使用 qsort 对它们进行排序。

#include<stdio.h>
int cmp(const int **a, const int **b) {
    //return 0;
    //return *a[1] - *b[1]
    // return *a - *b;
}
int main()
{
    int t; // test cases
    scanf("%d", &t);
    for(int i=0; i<t; i++)  {
        int n;
        scanf("%d", &n); // size of array
        int **arr = (int **)malloc(n * sizeof(int *)); 

        for(int j =0; j< n; j++) {
            arr[j] = (int *) malloc(2*sizeof(int));
        }
        for(int j =0; j< 2; j++) {
            for(int k =0; k< n; k++) {
              scanf("%d", &arr[k][j]);
            }
        }
        for(int k =0; k< n; k++) {
            for(int j =0; j<= 1; j++) {
             printf("%d\t", arr[k][j]);
            }
            printf("\n");
        }
       // qsort(arr, n, sizeof(arr[0]), cmp);
    }
    return 0;
}

所以对于输入,

1 2 
3 6 
0 8 
5 4 
8 9 
5 7

输出是,

1 2
5 4
3 6
5 7
0 8
8 9

我尝试过,但无法根据它们的第 2 列对它们进行排序。我对将数组元素传递给比较器感到困惑。还有什么作为元素的大小传递?但我猜下面的前两个是正确的。

qsort(arr, n, sizeof(arr[0]), cmp);
//qsort(arr, n, sizeof((int *)), cmp);
//qsort(arr, n, 2 * sizeof((int)), cmp);

我尝试了比较器的各种组合。

请指路或者解释一下。

【问题讨论】:

  • 我的输出和你完全不同。
  • @Stargateur。我根本没有任何输出,我只是打印了输入。我还没有对数组进行排序以获得输出。我只需要比较器功能的帮助。
  • 我不明白为什么有人反对它,一个理由会很好。并不是我没有尝试或做过一些研究。
  • 我没有否决你的问题,但也许我应该说你声称你的程序的输出是错误的,并且不清楚你试图用你的代码做什么。即使在文档中,也已经有大量问题显示了 qsort 的使用示例!
  • "传递什么作为元素的大小?" 提示:在 C 中,二维数组实际上是一维数组的一维数组。

标签: c arrays sorting comparator qsort


【解决方案1】:

比较函数的原型在qsort函数的原型中指定:

void qsort(void *base, size_t nmemb, size_t size,
           int (*compar)(const void *, const void *));

你的比较函数必须兼容,所以你可以这样定义:

int cmp(const void *a, const void *b) {
    /* a and b are pointers to the array of pointers. */
    int *aa = *(int * const *)a;
    int *bb = *(int * const *)b;
    return (aa[1] > bb[1]) - (aa[1] < bb[1]);
}

或者没有演员表:

int cmp(const void *a, const void *b) {
    /* a and b are pointers to the array of pointers. */
    int * const *aa = a;
    int * const *bb = b;
    int ia = (*aa)[1];
    int ib = (*bb)[1];
    return (ia > ib) - (ia < ib);
}

请注意,您不能使用简单的比较 aa[1] - bb[1],因为它可能会溢出较大的值,并且最多会产生不正确的输出。

此外,您输入的循环不正确:您应该以相反的顺序嵌套循环:

    for (int k = 0; k < n; k++) {
        for (int j = 0; j < 2; j++) {
           scanf("%d", &arr[k][j]);
        }
    }

这是修改后的版本:

#include <stdio.h>
#include <stdlib.h>

int cmp(const void *a, const void *b) {
    /* a and b are pointers to the array of pointers. */
    int * const *aa = a;
    int * const *bb = b;
    int ia = (*aa)[1];
    int ib = (*bb)[1];
    return (ia > ib) - (ia < ib);
}

int main() {
    int t; // test cases
    scanf("%d", &t);
    for (int i = 0; i < t; i++) {
        int n;
        scanf("%d", &n); // size of array
        int **arr = malloc(sizeof(*arr) * n);

        for (int j = 0; j < n; j++) {
            arr[j] = malloc(sizeof(*arr[j]) * 2);
        }
        for (int k = 0; k < n; k++) {
            for (int j = 0; j < 2; j++) {
                scanf("%d", &arr[k][j]);
            }
        }
        qsort(arr, n, sizeof(arr[0]), cmp);
        for (int k = 0; k < n; k++) {
            for(int j = 0; j < 2; j++) {
                printf("%d\t", arr[k][j]);
            }
            printf("\n");
        }
        for (int j = 0; j < n; j++) {
            free(arr[j]);
        }
        free(arr);
    }
    return 0;
}

您还可以使用实际的二维数组来简化代码:

#include <stdio.h>
#include <stdlib.h>

int cmp(const void *a, const void *b) {
    const int *aa = a;
    const int *bb = b;
    return (aa[1] > bb[1]) - (aa[1] < bb[1]);
}

int main() {
    int t; // test cases
    scanf("%d", &t);
    for (int i = 0; i < t; i++) {
        int n;
        scanf("%d", &n); // size of array
        int (*arr)[2] = malloc(sizeof(*arr) * n);

        for (int k = 0; k < n; k++) {
            scanf("%d%d", &arr[k][0], &arr[k][1]);
        }
        qsort(arr, n, sizeof(arr[0]), cmp);
        for (int k = 0; k < n; k++) {
            printf("%d\t%d\n", arr[k][0], arr[k][1]);
        }
        free(arr);
    }
    return 0;
}

【讨论】:

  • 你的意思是int cmp(const void *a, const void *b) 对吧?
  • @chqrlie。我知道const int *a 是什么意思,但*(const int * const *)a 是什么意思?
  • @SatishKumar:const int * const * 是指向int 数组的常量指针数组的常量指针类型。第一个const 实际上没用,我将删除它,第二个是为了避免编译器警告,如果要将常量指针const void * 转换为非常量指针int **
  • @AugustKarlstrom:当然,我最初的帖子是假的。
【解决方案2】:

首先,您没有二维数组。你有一个一维指针数组,每个指针指向一个一维数组int

所以你可以做的是对一维指针数组进行排序。为此,您可以编写一个比较函数来查看指向元素的值。

它可能看起来像:

int cmp(const void * a, const void * b)
{
    int* const * x = a;
    int* const * y = b;
    if ((*x)[1] < (*y)[1]) return -1;
    if ((*x)[1] > (*y)[1]) return 1;
    return 0;
}

如上所述:这是排序的指针数组。您可以像这样可视化它:

【讨论】:

  • 第一个consts(左起)不是必须的。
  • 这是什么意思,const int* const * x = a;?这与将 x(const) 类型转换为 int 是否相同
  • @SatishKumar 意思是:“将 x 声明为指向 const 指向 int 的指针”并将其初始化为值 a。需要将 void-pointer 转换为可以取消引用的指针。
猜你喜欢
  • 2010-09-24
  • 2019-04-27
  • 1970-01-01
  • 2014-10-10
  • 1970-01-01
  • 2018-03-26
  • 2015-02-10
相关资源
最近更新 更多