关于HashMap排序的一点浅见

原文:《关于HashMap排序的一点浅见》  作者:mgoann

我们在对hashmap进行排序的时候存在一定的误解,首先在这更正下~

我在遇到这个问题的时候也上网查了相关的资料,发现大家在进行hashmap进行排序的时候存在一定的了解误区。

有很多人认为把hashmap遍历一下,然后对其中的key和value进行排序,然后打印出来~

 

大家想一想,这样的hashmap排序根本就不是对hashmap进行排序~最多也只能称为hashmap遍历,hashmap的遍历问题很简单,网上也有很多相关的资料,下面我给出一个例程:

  1. public static void itHashMap(Map<Object, Object> m) {
  2.   Set set = m.entrySet();
  3.   Iterator it = set.iterator();
  4.   while(it.hasNext()) {
  5.    Map.Entry<Object, Object> me = (Map.Entry<Object, Object>)it.next();
  6.    System.out.println("key:" + me.getKey() + "----value" + me.getValue());
  7.   }
  8.  }

 

这个方法可以将hashmap遍历,并打印出相应的key和value!

 

其实,单纯的hashmap是无法实现排序的,我这里的排序是指,我们将键值对按照一定的顺序put进hashmap里,然后在进行取键值对的操作的时候,在按照put进去的顺序把键值对取出来。

 

下面我来浅显的解释下为什么不能排序.

  1. HashMap<String, Date> hm = new HashMap<String, Date>();
  2.         hm.put("1"new Date(8,10,1));
  3.         hm.put("3"new Date(8,10,3));
  4.         hm.put("2"new Date(8,10,2));
  5.         hm.put("5"new Date(8,10,5));
  6.         hm.put("9"new Date(8,10,9));
  7.         hm.put("8"new Date(8,10,8));
  8.         hm.put("6"new Date(8,10,6));
  9.         hm.put("7"new Date(8,10,7));

我在hashmap里按照以上的顺序放入9个键值对,然后我遍历hashmap打印出上面hm里的键值对:

key:3----value:Tue Nov 03 00:00:00 CST 1908
key:5----value:Thu Nov 05 00:00:00 CST 1908
key:7----value:Sat Nov 07 00:00:00 CST 1908
key:2----value:Mon Nov 02 00:00:00 CST 1908
key:9----value:Mon Nov 09 00:00:00 CST 1908
key:8----value:Sun Nov 08 00:00:00 CST 1908
key:6----value:Fri Nov 06 00:00:00 CST 1908
key:1----value:Sun Nov 01 00:00:00 CST 1908

我们从上面的结果可以看出,取出来的顺序并我们想要的顺序!

hashmap在put的时候是根据key的hashcode进行hash然后放入对应的地方!通过Debug可以看到HashMap的存放位置,网上有很多人说是随即存放,随即取,其实不然,放的时候是根据hashcode经过hash算法进行存放的,而我们取的时候也是想过key来取value。所以你取出来排完序,在放入HashMap的时候,它又把顺序打乱了~~(这里说的打乱也不是完全没有规律可循的,主要是你根据你的key来放的)!

 

所以我们要实现HashMap排序的时候就要借用别的集合来完成这个功能!

 

基本的思路是这样的,首先遍历HashMap取出相应的键值对,然后根据key或者是value进行排序,然后放入一个有序的集合当中,这样就实现了排序!

 

java在JDK1.4以后提供了LinkedHashMap来帮我们实现了有序的HashMap!

 

LinkedHashMap取键值对的时,是按照你放入的顺序来取的!

 

具体的排序算法有很多种~也可以自己写个冒泡排序取排列~~

 

再排完序以后,我们要找到key对应的vluae或是value对应的key!找key对应的vluea的时候很简单,网上有很多资料,我这里就不说了~~关键说说找value对应的key的时候,有的朋友就不知道该怎么做了~~

 

下面我提供两种思路

 

一种是我们可以把value放入一个数组,key也放入一个数组,这样在排序的时候按照value排序的时候,我们把key的位置也交换一次,这样就保证了键值对的完整性,见例程:

  1. private static void sortHashMap(HashMap<String, Date> hm) {
  2.                         
  3.         List<Date> dateListSorted = new ArrayList<Date> ();
  4.         
  5.         int size = hm.size();
  6.         Date[] dates = new Date[size];
  7.         Set set = hm.keySet();
  8.         Iterator iteratorSet = set.iterator();
  9.         int k = 0;
  10.         while(iteratorSet.hasNext()) {
  11.             String keyStr = (String)iteratorSet.next();
  12.             System.out.println("key from set----" + keyStr);
  13.             if(keyStr!=null && !(keyStr.length()<1)) {
  14.                 dates[k] = hm.get(keyStr);
  15.                 k++;    
  16.             }
  17.             System.out.println("value from hashmap----" + hm.get(keyStr));
  18.         }
  19.         iteratorList.next());
  20.         int sizeList = dates.length;
  21.         Object[] keyObj = set.toArray();
  22.         for(int i=0;i<sizeList;i++) {//冒泡排序
  23.             for(int j=i;j<sizeList;j++) {
  24.                 if(dates[j].after(dates[i])) {
  25.                 Date temp = dates[i];//交换value
  26.                 dates[i] = dates[j];
  27.                 dates[j] = temp;
  28.                 Object objectTemp = keyObj[i];//交换key
  29.                 keyObj[i] = keyObj[j];
  30.                 keyObj[j] = objectTemp;
  31.                 }
  32.                 
  33.             }
  34.         }
  35.         for(int i=0;i<keyObj.length;i++) {
  36.             System.out.println("key from array sorted----" + keyObj[i]);
  37.         }
  38.         for(int i=0;i<dates.length;i++) {
  39.             System.out.println("value from list sorted----" + dates[i]);
  40.         }
  41.         LinkedHashMap lhm = new LinkedHashMap();
  42.         for(int i=0;i<keyObj.length;i++) {//把经过排序的键值对放入Linked中
  43.             lhm.put(keyObj[i], dates[i]);
  44.         }
  45. /*
  46. *遍历Linkedhashmap打印出结果
  47. */
  48.         Set set1 = lhm.entrySet();
  49.         Iterator it = set1.iterator();
  50.         while(it.hasNext()) {
  51.             Map.Entry me = (Map.Entry)it.next();
  52.             System.out.println("key:" + me.getKey() + "----value" + me.getValue());
  53.         }
  54.     }

这种方法比较直观,可是效率比较低,而且对内存也很浪费,你想想,在这个过程中我们new了两个长度是hm.size()长度的数组,用于存放key和value,排序也是我们自己写的冒泡排序法~~

 

下面我介绍第二种方法:

 

第二种方法的思路是这样的,我们用hm.value()放回hm的vuale集合,再把它转换成一个数组,然后调用jdk给我们提供的Arrays.sort()方法去帮我们排序,这样效率会比自己写的冒泡排序法效率高的多!

 

在调用sort方法的时候我们需要写一个比较器,比较器的代码如下:

 

 

  1. package com.mgoann.test1;
  2. import java.util.Comparator;
  3. import java.util.Date;
  4. public final class DateComp implements Comparator {
  5.     public int compare(Object o1, Object o2) {
  6.         Date date1 = (Date)o1;
  7.         Date date2 = (Date)o2;
  8.         return date2.compareTo(date1);
  9.     }
  10.     
  11. }

剩下的就是更具value去找相应的key的问题了~~这里我用了一个for循环和Iterator去查找hm里的key,找到以后我们就放到LinkedHashMap里~,详见例程:

  1. package com.mgoann.test1;
  2. import java.util.Arrays;
  3. import java.util.Collection;
  4. import java.util.Comparator;
  5. import java.util.Date;
  6. import java.util.HashMap;
  7. import java.util.Iterator;
  8. import java.util.LinkedHashMap;
  9. import java.util.Map;
  10. import java.util.Set;
  11. public class Sort {
  12.     /**
  13.      * @param args
  14.      */
  15.     public static void main(String[] args) {
  16.         HashMap<String, Date> hm = new HashMap<String, Date>();
  17.         LinkedHashMap<String, Date> linkedHM = new LinkedHashMap<String, Date>();
  18.         hm.put("1"new Date(8,10,1));
  19.         hm.put("3"new Date(8,10,3));
  20.         hm.put("2"new Date(8,10,2));
  21.         hm.put("5"new Date(8,10,5));
  22.         hm.put("9"new Date(8,10,9));
  23.         hm.put("8"new Date(8,10,8));
  24.         hm.put("6"new Date(8,10,6));
  25.         hm.put("7"new Date(8,10,7));
  26.         itHashMap(hm);
  27.         linkedHM = sortHashMap(hm);
  28.         itHashMap(linkedHM);
  29.     }
  30.     private static LinkedHashMap sortHashMap(HashMap<String, Date> hm) {
  31.         
  32.         LinkedHashMap<String, Date> linkedHM = new LinkedHashMap<String, Date>();
  33.         final Comparator DATE_COMP = new DateComp();
  34.                 
  35.         int index = 0;
  36.             
  37.         Collection<Date> DateColl = hm.values();
  38.         Object[] dates = DateColl.toArray();
  39.         Arrays.sort(dates, DATE_COMP);
  40.         System.out.println("dates after sorted");
  41.         printElements(dates);
  42.         Set set = hm.entrySet();
  43.         for(int j=0;j<dates.length;j++) {
  44.             Iterator it = set.iterator();
  45.             while(it.hasNext()) {
  46.                 Map.Entry<String, Date> me = (Map.Entry<String, Date>)it.next();
  47.                 if(dates[j].equals(me.getValue())) {
  48.                     linkedHM.put(me.getKey(), me.getValue());
  49.                 }
  50.             }
  51.         }
  52.         return linkedHM;
  53.     }
  54.     
  55.     public static void printElements(Collection c) {
  56.         Iterator it = c.iterator();
  57.         while(it.hasNext()) {
  58.             System.out.println(it.next());
  59.         }
  60.     }
  61.     
  62.     public static void printElements(Object[] dates) {
  63.         for(int i=0;i<dates.length;i++) {
  64.             System.out.println(dates[i]);
  65.         }
  66.     }
  67.     
  68.     public static void itHashMap(Map<String, Date> m) {
  69.         Set set = m.entrySet();
  70.         Iterator it = set.iterator();
  71.         while(it.hasNext()) {
  72.             Map.Entry<String, Date> me = (Map.Entry<String, Date>)it.next();
  73.             System.out.println("key:" + me.getKey() + "----value:" + me.getValue());
  74.         }
  75.     }
  76. }

这样我们就实现了HashMap的排序问题!

 

程序运行结果如下:

key:3----value:Tue Nov 03 00:00:00 CST 1908
key:5----value:Thu Nov 05 00:00:00 CST 1908
key:7----value:Sat Nov 07 00:00:00 CST 1908
key:2----value:Mon Nov 02 00:00:00 CST 1908
key:9----value:Mon Nov 09 00:00:00 CST 1908
key:8----value:Sun Nov 08 00:00:00 CST 1908
key:6----value:Fri Nov 06 00:00:00 CST 1908
key:1----value:Sun Nov 01 00:00:00 CST 1908
dates after sorted
Mon Nov 09 00:00:00 CST 1908
Sun Nov 08 00:00:00 CST 1908
Sat Nov 07 00:00:00 CST 1908
Fri Nov 06 00:00:00 CST 1908
Thu Nov 05 00:00:00 CST 1908
Tue Nov 03 00:00:00 CST 1908
Mon Nov 02 00:00:00 CST 1908
Sun Nov 01 00:00:00 CST 1908
key:9----value:Mon Nov 09 00:00:00 CST 1908
key:8----value:Sun Nov 08 00:00:00 CST 1908
key:7----value:Sat Nov 07 00:00:00 CST 1908
key:6----value:Fri Nov 06 00:00:00 CST 1908
key:5----value:Thu Nov 05 00:00:00 CST 1908
key:3----value:Tue Nov 03 00:00:00 CST 1908
key:2----value:Mon Nov 02 00:00:00 CST 1908
key:1----value:Sun Nov 01 00:00:00 CST 1908


有人质疑:

第二种方法,根据value去找相应的key的问题:如果两个key对应相同的Value,你的算法是否就无效了!?
把比较器修改成Map.Entry&lt;String, Date&gt;对象的比较,然后直接用Array.sort(Map.Entry&lt;String, Date&gt;[]),不是更方便?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值