最有效的方法来增加在Map中的值

关于这个是在一个博客上看到的,就像试一下,测试结果出人意料。

看到这个标题可能还是觉得有点抽象,那么首先来一段代码:

int count = map.containsKey(string) ? map.get(string) : 0;
map.put(string, count + 1);

其中contains(),get() and put()方法都要在map中根据key查找,需要朝找三次,那么在优化过后只需要查找一次。

以上这段代码以及稍后的优化思路来自:http://blog.pengyifan.com/most-efficient-way-to-increment-a-map-value-in-java-only-search-the-key-once/

这是干什么用的,那么在直接看下面的一个应用就很清楚了,代码如下:

/** 
	    * 给你一组字符串 如 {5,2,3,2,4,5,1,2,1,5},让你输出里面出现次数最多且数值最大的一个,出现几次  
	    * 优点:时间复杂度为O(n) 
	    * 缺点:暂时没发现 
	    */  
	   public static void method2(){  
	      
	    int[] datas = {5,2,3,2,4,5,1,2,1,5};  
	    Map<Integer,Integer> map = new HashMap<Integer, Integer>();  
	    for (int i = 0; i < datas.length; i++) {  
	        Integer key = datas[i];  
	        Integer value = map.get(key);  //****//
	        if(value != null){  
	            map.put(key, ++value);  //****//
	        }else{  
	            map.put(key, 1);  
	        }  
	    }  
	      
	    int maxTime = 0;  
	    int maxTime_num = 0;  
	    Set<Integer> keySet = map.keySet();  
	    Iterator<Integer> it = keySet.iterator();  
	    while(it.hasNext()){  
	        Integer key = it.next();  
	        Integer value = map.get(key);  
	        System.out.println(key+":"+value);  
	          
	        if(value >= maxTime){  
	            maxTime = value;  
	            if(key > maxTime_num){  
	                maxTime_num = key;  
	            }  
	        }  
	    }  
	    System.out.println("出现次数最多:"+maxTime+"次;且最大的数是:"+maxTime_num);  
	      
	   }  
这段代码是以前写的:http://blog.csdn.net/wufengui1315/article/details/39226103

关于这个算法题还写了一种基于数组的实现,当然这不是本篇文章的重点,有兴趣可以看下。

然后我写了一个测试用例:

public static void main(String[] args) throws UnsupportedEncodingException {
	
		//System.out.println(addWithoutArithmetic(2,15));
		//System.out.println(addWithoutArithmetic(5,17));
		int length = 10000000*2;
		 int[] datas = new int[length];  
		 for (int i = 0; i < datas.length; i++) {
			 datas[i] = (int) (Math.random()*(length/2));
		}
		method2(datas);
		method3(datas);
		method4(datas);
	}
其中method2,method3,method4与上面的基本一样,不同的部分按顺序如下:

Map<Integer,MutableInteger> map = new HashMap<Integer, MutableInteger>();
	    for (int i = 0; i < datas.length; i++) {  
	        Integer key = datas[i];  
	        MutableInteger count = map.get(key);
	        if (count != null) {
	          count.set(count.get() + 1);
	        } else {
	          map.put(key, new MutableInteger(1));
	        }
	        
	    }  

Map<Integer,Integer> map = new HashMap<Integer, Integer>();  
		    for (int i = 0; i < datas.length; i++) {  
		        Integer key = datas[i];  
		        Integer value = map.get(key);  
		        if(value != null){  
		            map.put(key, ++value);  
		        }else{  
		            map.put(key, 1);  
		        }  
		    }  

Map<Integer,Integer> map = new HashMap<Integer, Integer>();  
		    for (int i = 0; i < datas.length; i++) {  
		        Integer key = datas[i];  
		        Integer value = map.containsKey(key)? map.get(key):1;  
		        map.put(key, value+1);  
		    }  

打印结果:

出现次数最多:13次;且最大的数是:4814069
time:12614
出现次数最多:13次;且最大的数是:4814069
time:8662
出现次数最多:14次;且最大的数是:4814069
time:8287

-------------------------------------

结果与原博客所说的相差很远,本来说效率最高的花的时间最多,效率最差的却花的时间最少。

尴尬

经过多次测试,结果很稳定,与上面类似,

那么,为什么会这样?

map中的查找并不是顺序查找,而是根据哈希值查找,查找速度很快。我只能这样理解。


写到这里,想起之前的有个是基于数组的写法(O(n)),就是method1(),然后重新跑了几遍,结果如下:

method1()在这里有写:http://blog.csdn.net/wufengui1315/article/details/39226103

出现次数最多:13次;且最大的数是:9972122
time:17053
出现次数最多:13次;且最大的数是:9972122
time:10130
出现次数最多:14次;且最大的数是:9972122
time:9166
最多的出现13次
出现次数最多:13次;且最大的数是:9972122    //(method1())
time:569

结果还是基于数组的最快,看数据很清楚了。




发布了52 篇原创文章 · 获赞 8 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/wufengui1315/article/details/47265323
今日推荐