c语言 - 此比较函数如何工作



我知道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. 即使它返回值,也应按递增顺序打印它们。为什么它以降序显示它们?

这个比较函数很奇怪。
为了理解它是如何工作的,让我们开始考虑 qsort 期望什么:它期望一个接受 2 个数字的函数,ab,以及

返回小于、等于或大于

0 的整数,如果第一个参数分别被视为小于、等于或大于第二个参数。

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

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

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

让我们取 30 和 4。如果将它们连接起来,则会得到"304""430"。由于 304 <430,该函数告诉您最大数字为 4。因此,从这个角度来看,4> 30,这与数字排序相反。

如果你取 3 和 30,两种可能的串联是"330""303",由于 330> 303,你必须首先取 3,函数告诉你 3> 30。同样,它与数字排序相反。

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

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

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

因此,该函数比较ab并返回:

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

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

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];

如果要按递增顺序查看它们,请将其更改为:

return arr[i] - brr[i];

相关内容

  • 没有找到相关文章

最新更新