使用java比较器对字符数组进行排序

Posted

技术标签:

【中文标题】使用java比较器对字符数组进行排序【英文标题】:Sort character array using java comparator 【发布时间】:2022-01-20 07:26:38 【问题描述】:

按字典顺序对字符数组进行排序,附加条件是所有 c 都在所有 b 之前。这可以手动完成,但我想使用比较器通过内置排序对其进行编码。我写的代码-

static class Sort implements Comparator<Character> 
    @Override
    public int compare(Character x, Character y) 
        if(x == 'c' && y == 'b') 
            return y - x;
        
        return x - y;
    


public static void main(String[] args) 
    String s = "abracadabra";
    int n = s.length();
    Character[] res = new Character[n];
    for (int i = 0; i < n; i++) 
        res[i] = s.charAt(i);
    
    Arrays.sort(res, new Sort());
    System.out.println(Arrays.toString(res));

给出输出:[a, a, a, a, a, b, c, b, d, r, r]。 c 只出现在 b 之一之前。如果我将比较器更改为以下,那么它会给出正确的输出。

public int compare(Character x, Character y) 
        if(x == 'c' && y == 'b' || x == 'b' && y == 'c') 
            return y - x;
        
        return x - y;
    

我的问题是为什么在这两种情况下返回“y-x”都会给出正确答案?如果在一种情况下返回“y-x”是正确的,那么在另一种情况下不应该返回“x-y”是正确的吗?而不是“y-x”,返回 -1 或 +1 也不起作用。 PL。解释内部发生的事情。谢谢!

【问题讨论】:

如果你反转参数,你必须否定结果。 【参考方案1】:

问题在于,如果传递 'c''b' 使比较返回负值,那么传递 'b''c' 应该返回正值(在这种情况下,您的第一个版本返回负数反而)。如果无论参数的顺序如何,函数都没有返回一致的结果,那么排序算法就会产生垃圾顺序。

考虑这个版本:

    public int compare(Character x, Character y) 
        if (x == 'c' && y == 'b') 
            return -1;
         else if (x == 'b' && y == 'c') 
            return 1;
         else 
            return x.compareTo(y);
        
    

【讨论】:

(我不太喜欢使用减法来比较两个值;在这样做的 C 程序中曾多次遇到溢出问题)【参考方案2】:

您可以添加System.out.println()以了解其工作原理:

代码

import java.util.Arrays;
import java.util.Comparator;

public class Main 

    public static void main(String[] args) 
        String s = "abracadabra";
        int n = s.length();
        
        System.out.println("X Y\tX Y\t[if] VALUE");
        System.out.println();
        
        Character[] res = new Character[n];
        for (int i = 0; i < n; i++) 
            res[i] = s.charAt(i);
        
        
        int min = 'a';
        
        Arrays.sort(res, new Comparator<Character>() 

            @Override
            public int compare(Character x, Character y) 
                System.out.print(y + " " + x + "\t" + (x-min) + " " + (y-min) + "\t");
                if(x == 'c' && y == 'b') 
                    System.out.println("true " + (y - x));
                    return y - x;
                
                System.out.println("     " + (x - y));
                return x - y;
            
        );
        System.out.println("#################################\nResult:\n" + Arrays.toString(res));
    


控制台:

X Y X Y   [if] VALUE

a b 1 0        1
b r 17 1       16
r a 0 17       -17
b a 0 1        -1
a a 0 0        0
b c 2 1   true -1
a c 2 0        2
c a 0 2        -2
a a 0 0        0
c d 3 2        1
r d 3 17       -14
b d 3 1        2
c a 0 2        -2
a a 0 0        0
a a 0 0        0
c b 1 2        -1
a b 1 0        1
a b 1 0        1
b r 17 1       16
d r 17 3       14
r r 17 17      0
c a 0 2        -2
a a 0 0        0
b a 0 1        -1
a a 0 0        0
#################################
Result:
[a, a, a, a, a, b, c, b, d, r, r]

【讨论】:

【参考方案3】:

请参阅Javadoc for java.util.Comparator。上面写着compare()的方法:

比较它的两个参数的顺序。返回负整数、零或正整数,因为第一个参数小于、等于或大于第二个参数。

对于您的情况,这意味着 compare( 'b', 'c' ) 应该返回大于零的值,对于 compare( 'c', 'b' ) 应该返回小于零的值,而自然顺序则相反。

但是你的第一个实现(那个错误的那个)只涵盖了compare( 'c', 'b' ) 的情况,而不是compare( 'b', 'c' ),因此该方法将返回默认值。

您的第二个正常工作的实施解决了这个问题。

【讨论】:

以上是关于使用java比较器对字符数组进行排序的主要内容,如果未能解决你的问题,请参考以下文章

Java中怎么对数组中的字符串进行排序

Java:以数字方式对字符串数组进行排序

javascript sort()对数组中的元素进行排序

java12 - 7 排序的案例

使用冒泡排序对Java中的名称数组按字母顺序排序

如何通过比较字符串出现的位置来对字符串列表进行排序?