这个比较函数如何工作?

时间:2017-03-08 20:04:20

标签: c compare qsort

我已经理解compare函数正在对值进行排序,以便按递减顺序显示数字组合。

例如:给定[3, 30, 34, 5, 9],最大的数字是9534330

 int compare(const void *a1,const void *b1){
        int a = *(int*)a1;
        int b = *(int*)b1;
        int i=0;
        char arr[10000]={0};
        char brr[10000]={0};
        sprintf(arr, "%d%d", a, b);
        sprintf(brr, "%d%d", b, a);
        int k = strlen(arr);
        for(i=0; i < k; i++){
            if(arr[i] != brr[i])
                return brr[i] - arr[i];
        }
        return b-a;
    }
    char* largestNumber(const int* A, int n1) {
        char *ans = (char*) calloc(10000000,sizeof(char));
        int i=0, count=0;
         qsort(A, n1, sizeof(int), compare);
        if(A[0] == 0){  
            ans[0] = '0'; ans[1]=0; return ans;
        }
        for(i=0; i<n1; i++){
            int k = A[i];
            // printf("%d ", k);
            count += sprintf(ans+count, "%d", k);
        }
        // printf("\n");
        ans[count] = 0;
        return ans;
    }

我的怀疑如下:

  1. 这段代码如何运作?

    for(i=0; i < k; i++){
        if(arr[i] != brr[i])
            return brr[i] - arr[i];
    }
    

    它正在比较arrbrr的内容,但是如何返回值以便以这种方式对值进行排序?

  2. 即使它返回值,也应按递增顺序打印。为什么它按降序显示?

1 个答案:

答案 0 :(得分:0)

这个比较功能很奇怪 要了解其工作原理,让我们开始考虑what qsort expects:它需要一个接受2个数字的函数,ab,以及

  如果第一个参数被认为分别小于,等于或大于第二个参数,则

返回小于,等于或大于0的整数。

在这种情况下,正如我们将看到的,它实际上返回相反的结果,即,如果考虑 second 参数,它返回小于,等于或大于0的整数分别小于,等于或大于第一。这只是因为此代码的作者希望按降序排序而不是按升序排序。

那就是说,这个比较功能是一个特殊的功能:让我们看看它的作用。虽然它适用于数字(它接受void*,这是一个通用指针,但它然后将两个参数都转换为int*并取消引用它们),它不会在数字上对它们进行比较,甚至不能在数字上进行比较经典的字母数字方式。 相反,它指示一旦转换为字符串,两个数字的顺序必须连接起来以生成数字序列,这些数字被解释为数字,产生最大可能结果(这是由另一个函数的名称暗示的) ,largestNumber)。它通过指示必须首先采用的最大数字来实现。这听起来很复杂,但有些例子会澄清。

让我们取数字3和4.如果你把它们当作字符串("3""4"),你可以用两个不同的顺序连接它们,得到"34"或{{1 }}。现在,将这些字符串转换回数字:哪一个更大?显然,34&lt; 43,如果你想要最大的数字(43),你必须把4作为第一个数字,3作为第二个。在这种情况下,函数将告诉您最大数字是4.它通过返回一个正数(在这种情况下为1)来实现。

我们取而代之的是30和4。如果您连接它们,则会得到"43""304"。从304&lt; 430,该函数告诉你最大数是4.因此,从这个观点来看,4> 30,这是数字排序的反面。

如果你选择3和30,那么两个可能的连接是"430""330",并且因为330&gt; 303你必须先拿3,该功能告诉你3&gt; 30.同样,它与数字排序相反。

如果您选择30和30,则必须在"303""3030"之间进行选择,它们是相同的,在这种情况下,函数返回0.

现在是一个棘手的案例:如果比较3和33,两个“字符串化”数字是相同的("3030""333"),所以我们期望0.实际上在这种情况下函数告诉你最大的数字是第二个...但是没关系,因为结果是相同的。

这种比较究竟如何运作?首先,使用"333"将数字转换为字符串。考虑到2个字符串(让我们称之为sprintf"ab")必须具有相同的长度,因此它使用"ba"检查一个字符串的长度,然后循环检查每个数字,开始从第一个。如果strlenab之间的数字相同,则它什么都不做,只是转到下一个;如果它不同,则比较它们并返回ba的数字减去brr的数字。例如,当比较3和30时,arr将包含330和arr 303.在第一次迭代(当brr时)它将检查第一个数字:两者都是3,所以你不能选择哪个数字更高。移至第二位:3&gt; 0,所以i==0&gt; arr,因此该函数必须返回一个负数,事实确实如此:它返回brr

因此,该函数会比较0 - 3 = -3a并返回:

  • 如果通过按此顺序连接它们产生最大数字,则为负数(a,b);
  • 0,如果数字相同,那么它们采取的顺序无关紧要;
  • 如果必须以相反的顺序(b,a)连接以产生最大数字,则为正数。

此表显示了经典数字排序,经典字母数字排序和此自定义排序(我称之为“最大字符串数字排序”)的结果

b

至于为什么它们按递减顺序打印,只是因为这一行:

 a   b    Numeric sort   Alphanumeric sort   Largest stringified number sort
 3   4      3 <   4          3 <   4            34 <    43  --> return  1 >  0 -->  3  <  4
30   4     30 >   4         30 <   4           304 <   430  --> return  1 >  0 -->  30 <  4
 3  30      3 <  30          3 <  30           330 >   303  --> return -3 <  0 -->  3  > 30
 3  31      3 <  31          3 <  31           331 >   313  --> return -2 <  0 -->  3  > 31
 3  32      3 <  32          3 <  32           332 >   323  --> return -1 <  0 -->  3  > 32
 3  33      3 <  33          3 <  33           333 ==  333  --> return 30 >  0 -->  3  < 33
 3  34      3 <  34          3 <  34           334 <   343  --> return  1 >  0 -->  3  < 34
30  30     30 == 30         30 == 30          3030 == 3030  --> return  0 == 0 --> 30 == 30

如果您想按升序查看它们,请将其更改为:

return brr[i] - arr[i];