排序的Java自定义排序

时间:2013-08-05 20:31:01

标签: java algorithm sorting

实现Java比较器以使用自定义排序对集合进行排序的最佳方式(在时间和空间效率方面)是什么。例如 - 我想使用以下顺序对数组进行排序 -

RWQOJMVAHBSGZXNTCIEKUPDYFL

我有以下Java代码,它按预期工作,但不确定是否有任何其他有效的方法来执行相同的操作。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.lang.Math;

public class DiffSort {

    private static String order = "RWQOJMVAHBSGZXNTCIEKUPDYFL";

    // sort with comparator
    public static Comparator<String> diffNaturalOrder = new Comparator<String>() {
        public int compare(String v, String w) {
            int diff = 0, iter = 0;
            Integer index1, index2;
            Integer len1 = v.length();
            Integer len2 = w.length();
            int len = Math.min(len1, len2); // lesser of 2 strings

            for(int i=0; i<len; i++) {
                index1 = order.indexOf(v.charAt(i));
                index2 = order.indexOf(w.charAt(i));
                // if both chars are absent in order string, use natural ordering
                if(index1 == -1 && index2 == -1)
                    diff = new Character(v.charAt(i)).compareTo(new Character(w.charAt(i)));
                else if(index1 == -1 && index2 > 0)
                    diff = 1;
                else if(index1 > 0 && index2 == -1)
                    diff = -1;
                else
                    diff = index1.compareTo(index2);
                // break if we found mismatch
                if(diff != 0) break;
            }

            // return smaller string first in sort
            if(diff == 0)
                diff = len1.compareTo(len2);
            return diff;
        }
    };

    // test client
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("ABCE1!4");
        list.add("ABCE1!7");
        list.add("!SDF");
        list.add("TRWESF!");
        Collections.sort(list, DiffSort.diffNaturalOrder);

        // print sorted array
        for(String s:list)
            System.out.println(s);
    }
}

/ * OUTPUT * /

ABCE1!4

ABCE1!7

TRWESF!

!SDF

4 个答案:

答案 0 :(得分:5)

order的所有字符放入Map<Character, Integer>(整数对应于order中字符的位置),然后放入for - 循环中order.indexOf(c)使用map.get(c)

您可以非常轻松地设置此地图:

private static final Map<Character, Integer> map = 
                                new HashMap<Character, Integer>(order.length());

static {
    for (int i = 0; i < order.length(); i++)
        map.put(order.charAt(i), i);
}

答案 1 :(得分:2)

我还要做的是缓存char的位置计算。

首先,w会在检查地图之前比较字符相等。

然后在map中会存储char的每个组合。

(左,右)

如果离开更早,则返回1  如果权利较早,则返回-1  如果左边的eq右边返回0.

或者你可以创建一个char数组,并在char的位置存储顺序。

public final class CustomAlphabetComparator implements Comparator<String> {

        private char order[] = new char[1<<16];


        public CustomAlphabetComparator (String alphabet) {
            if (alphabet == null) throw new IllegalArgumentException("Input must not be null");

            char index = 0;

            for(char c : alphabet.toCharArray()) {
                order[c] = index++;
            }
        }


        @Override
        public int compare(String o1, String o2) {

            if(o1 == o2) return 0; //We check the references

            if(o1 == null && o2 == null) return  0;
            if(o1 != null && o2 == null) return  1;
            if(o1 == null && o2 != null) return -1;

            if(o1.equals(o2)) return 0; //We check that are equal

            char[] c1 = o1.toCharArray();
            char[] c2 = o2.toCharArray();

            int shortest = c1.length < c2.length ? c1.length : c2.length;
            int result = 0;

            for(int i = 0; result == 0 & i < shortest; i++ ) {

                result = order[c1[i]] - order[c2[i]];

            }

            return result;
        }

    }

答案 2 :(得分:0)

显然你所使用的代码是有效的,但有一点需要注意的是String.indexOf(ch)逐个字符地逐字符串,直到找到它正在查找的字符串。如果您的字符串接近“字母表”的末尾,则会产生大量不必要的循环。

我将排序存储在HashMap<Character, Integer>中,并在恒定时间内从中提取索引信息。应该比循环整个String更快(对于你要比较的每个角色!)......

答案 3 :(得分:0)

这是一个只有大写英文字母的有效比较器(可以扩展,但不是没有限制):

public static Comparator<String> diffNaturalOrder = new Comparator<String>() {
    private int[] order = new int[] {7, 9, 16, 22, 18, 24, 11, 8, 17, 4, 19, 25, 5, 14, 3, 21, 2, 0, 10, 15, 20, 6, 1, 13, 23, 12};
    public int compare(String v, String w) {
        int diff = 0;
        int len = Math.min(v.length(), w.length()); // lesser of 2 strings
        int o1, o2;
        for(int i=0; i<len; i++) {
            o1 = order[v.charAt(i)-65];
            o2 = order[w.charAt(i)-65];
            diff = o1 - o2;
            // break if we found mismatch
            if(diff != 0) break;
        }
        if (diff == 0) {
            diff = v.length() - w.length();
        }
        return diff;
    }
};

而不是indexOfMap<Character, Integer>,它使用char的整数值(小于65)来索引包含排序数据的数组。可以这样生成数组:

private static void generateArray() {
    String order = "RWQOJMVAHBSGZXNTCIEKUPDYFL";
    int[] chars = new int[26];
    int i = 0;
    for (char c : order.toCharArray()) {
        chars[c-65] = i++;
    }
    System.out.println(Arrays.toString(chars));
}