美文网首页
十分钟探讨map与hashmap的排序

十分钟探讨map与hashmap的排序

作者: a9b430bb6daa | 来源:发表于2017-07-24 18:32 被阅读24次

    今天遇到一个关于map排序的问题,做个笔记(__) 嘻嘻……

    既然遇到了,就不如挖它祖坟看一看里面的究竟,说不定找到价值连城的古董或者什么的,也说不准,下面,我们就一起带着铲子和摸金校尉,一起去探个究竟吧_

    老规矩,先上代码,有代码有真相,如下所示:

    /**
     * 
     * Created by zero on 2016-6-11
     *
     */
    public class HashMapSort
    {
        public static void main(String[] args) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("b", 1 + "");
            map.put("cds", 1 + "");
            map.put("daac", 23 + "");
            map.put("ass", 3 + "");
            map.put("daaa", 21 + "");
            map.put("f", 2 + "");
            map.put("daaz", 25 + "");
            map.put("e", 22 + "");
    
            List<Map.Entry<String, Object>> list = new ArrayList<Map.Entry<String, Object>>(
                    map.entrySet());
            Collections.sort(list, new Comparator<Map.Entry<String, Object>>()
            {
                
                public int compare(Entry<String, Object> o1,
                        Entry<String, Object> o2) {
    //              // 按key升序排序
                    return o1.getKey().compareTo(o2.getKey());
    //              // 按key降序排序
    //              return o2.getKey().compareTo(o1.getKey());
    //              // 把value转化成String升序排序
    //              return ((String) o1.getValue()).compareTo((String) o2.getValue());
    //              // 把value转化成String降序排序
    //              return ((String) o2.getValue()).compareTo((String) o1.getValue());
                }
    
            });
    
            for (Map.Entry<String, Object> mapping : list)
            {
                System.out.println(mapping.getKey() + "=" + mapping.getValue());
            }
        }
    }
    

    我们采用的是key的升序排序,执行后的结果是这个样子的

    ass=3
    b=1
    cds=1
    daaa=21
    daac=23
    daaz=25
    e=22
    f=2
    

    那很多人要说了,我们的产品需要的是降序或者是value排序,那也很简单,只要改return那行代码就好,但是有一点要强调的是,compareTo前后的数据类型要一致,String、Long、Integer等都支持,或者更准确的说,只要实现Comparable接口的都支持,这个接下来会举例分析,现在,我们先看下sort这个函数,在Collections中有两个sort方法,如下所示:

    public static <T extends Comparable<? super T>> void sort(List<T> list) {
            Object[] a = list.toArray();
            Arrays.sort(a);
            ListIterator<T> i = list.listIterator();
            for (int j=0; j<a.length; j++) {
                i.next();
                i.set((T)a[j]);
            }
        }
       
    public static <T> void sort(List<T> list, Comparator<? super T> c) {
            Object[] a = list.toArray();
            Arrays.sort(a, (Comparator)c);
            ListIterator<T> i = list.listIterator();
            for (int j=0; j<a.length; j++) {
                i.next();
                i.set((T)a[j]);
            }
        }
    

    第一个sort方法,是根据元素的自然顺序对指定列表按升序进行排序。列表中的所有元素都必须实现 Comparable 接口(根据刚刚的介绍,是不是想到了什么?String、Long、Integer等,当然,也可以自己手写去实现接口)。此外,列表中的所有元素都必须是可相互比较的(也就是说,对于列表中的任何 e1 和 e2 元素,e1.compareTo(e2) 不得抛出 ClassCastException)。
    此排序方法具有稳定性:不会因调用 sort 方法而对相等的元素进行重新排序。

    指定列表必须是可修改的,但不必是大小可调整的。

    该排序算法是一个经过修改的合并排序算法(其中,如果低子列表中的最高元素小于高子列表中的最低元素,则忽略合并)。此算法提供可保证的 n log(n) 性能。 此实现将指定列表转储到一个数组中,并对数组进行排序,在重置数组中相应位置处每个元素的列表上进行迭代。这避免了由于试图原地对链接列表进行排序而产生的 n2 log(n)(PS:此处2为平方,忘记平方怎么打了,O(∩_∩)O~) 性能。

    我们着重看下第二个sort方法,参数:
    ·list - 要排序的列表。
    ·c - 确定列表顺序的比较器。null 值指示应该使用元素的自然顺序。

    抛出:
    ·ClassCastException - 如果列表中包含不可使用指定比较器相互比较 的元素。
    ·UnsupportedOperationException - 如果指定列表的列表迭代器不支持 set 操作。

    根据指定比较器产生的顺序对指定列表进行排序。此列表内的所有元素都必须可使用指定比较器相互比较(也就是说,对于列表中的任意 e1 和 e2 元素,c.compare(e1, e2) 不得抛出 ClassCastException)。
    此排序被保证是稳定的:不会因调用 sort 而对相等的元素进行重新排序。

    排序算法是一个经过修改的合并排序算法(其中,如果低子列表中的最高元素小于高子列表中的最低元素,则忽略合并)。此算法提供可保证的 n log(n) 性能。 指定列表必须是可修改的,但不必是可大小调整的。此实现将指定列表转储到一个数组中,并对数组进行排序,在重置数组中相应位置每个元素的列表上进行迭代。这避免了由于试图原地对链接列表进行排序而产生的 n2 log(n) 性能。

    下面,我们在通过最初代码将Object转换成String,通过value降序排序,就像上述说所得那样,只要打开return就ok,如下:

    public class HashMapSort
    {
        public static void main(String[] args) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("b", 1 + "");
            map.put("cds", 1 + "");
            map.put("daac", 23 + "");
            map.put("ass", 3 + "");
            map.put("daaa", 21 + "");
            map.put("f", 2 + "");
            map.put("daaz", 25 + "");
            map.put("e", 22 + "");
    
            List<Map.Entry<String, Object>> list = new ArrayList<Map.Entry<String, Object>>(
                    map.entrySet());
            Collections.sort(list, new Comparator<Map.Entry<String, Object>>()
            {
                
                public int compare(Entry<String, Object> o1,
                        Entry<String, Object> o2) {
    //              // 按key升序排序
    //              return o1.getKey().compareTo(o2.getKey());
    //              // 按key降序排序
    //              return o2.getKey().compareTo(o1.getKey());
    //              // 把value转化成String升序排序
    //              return ((String) o1.getValue()).compareTo((String) o2.getValue());
    //              // 把value转化成String降序排序
                    return ((String) o2.getValue()).compareTo((String) o1.getValue());
                }
    
            });
    
            for (Map.Entry<String, Object> mapping : list)
            {
                System.out.println(mapping.getKey() + "=" + mapping.getValue());
            }
        }
    }
    

    运行结果

    ass=3
    daaz=25
    daac=23
    e=22
    daaa=21
    f=2
    b=1
    cds=1
    

    这个value降序排序是不是有点出乎想象?我们采用的是Object转String,这真的是value降序排序吗?带着这个疑问去打开String源码找到compareTo方法,如下所示:

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
    
    ..................省略太多代码,只看核心代码.......................
    
    public int compareTo(String anotherString) {
            int len1 = value.length;
            int len2 = anotherString.value.length;
            int lim = Math.min(len1, len2);
            char v1[] = value;
            char v2[] = anotherString.value;
    
            int k = 0;
            while (k < lim) {
                char c1 = v1[k];
                char c2 = v2[k];
                if (c1 != c2) {
                    return c1 - c2;
                }
                k++;
            }
            return len1 - len2;
        }
    }
    

    如果自己打开源码,上面会有一些注释,大致意思是按字典顺序比较两个字符串。该比较基于字符串中各个字符的 Unicode 值。按字典顺序将此 String 对象表示的字符序列与参数字符串所表示的字符序列进行比较。如果按字典顺序此 String 对象位于参数字符串之前,则比较结果为一个负整数。如果按字典顺序此 String 对象位于参数字符串之后,则比较结果为一个正整数。如果这两个字符串相等,则结果为 0;compareTo 只在方法 equals(Object) 返回 true 时才返回 0。

    今天的笔记到此为止,一不小心又是凌晨了,这篇只是简单浏览了一遍,没做过多检查,如有错误,欢迎批评指正,好困,睡觉了(~﹃~)~zZ

    微信扫我,_

    相关文章

      网友评论

          本文标题:十分钟探讨map与hashmap的排序

          本文链接:https://www.haomeiwen.com/subject/crzbkxtx.html