步骤 1 : List查找的低效率html
假设在List中存放着无重复名称,没有顺序的2000000个Hero
要把名字叫作“hero 1000000”的对象找出来
List的作法是对每个进行挨个遍历,直到找到名字叫作“hero 1000000”的英雄。
最差的状况下,须要遍历和比较2000000次,才能找到对应的英雄。
测试逻辑:java
package collection; import java.util.ArrayList; import java.util.Collections; import java.util.List; import charactor.Hero; public class TestCollection { public static void main(String[] args) { List<Hero> heros = new ArrayList<Hero>(); for (int j = 0; j < 2000000; j++) { Hero h = new Hero("Hero " + j); heros.add(h); } // 进行10次查找,观察大致的平均值 for (int i = 0; i < 10; i++) { // 打乱heros中元素的顺序 Collections.shuffle(heros); long start = System.currentTimeMillis(); String target = "Hero 1000000"; for (Hero hero : heros) { if (hero.name.equals(target)) { System.out.println("找到了 hero!" ); break; } } long end = System.currentTimeMillis(); long elapsed = end - start; System.out.println("一共花了:" + elapsed + " 毫秒"); } } }
步骤 2 : HashMap的性能表现算法
使用HashMap 作一样的查找数组
package collection; import java.util.HashMap; import charactor.Hero; public class TestCollection { public static void main(String[] args) { HashMap<String,Hero> heroMap = new HashMap<String,Hero>(); for (int j = 0; j < 2000000; j++) { Hero h = new Hero("Hero " + j); heroMap.put(h.name, h); } System.out.println("数据准备完成"); for (int i = 0; i < 10; i++) { long start = System.currentTimeMillis(); //查找名字是Hero 1000000的对象 Hero target = heroMap.get("Hero 1000000"); System.out.println("找到了 hero!" + target.name); long end = System.currentTimeMillis(); long elapsed = end - start; System.out.println("一共花了:" + elapsed + " 毫秒"); } } }
步骤 3 : HashMap原理与字典dom
在展开HashMap原理的讲解以前,首先回忆一下你们初中和高中使用的汉英字典。性能
好比要找一个单词对应的中文意思,假设单词是Lengendary,首先在目录找到Lengendary在第 555页。学习
而后,翻到第555页,这页不仅一个单词,可是量已经不多了,逐一比较,很快就定位目标单词Lengendary。测试
555至关于就是Lengendary对应的hashcodecode
步骤 4 : 分析HashMap性能卓越的缘由htm
-----hashcode概念-----
全部的对象,都有一个对应的hashcode(散列值)
好比字符串“gareen”对应的是1001 (实际上不是,这里是方便理解,假设的值)
好比字符串“temoo”对应的是1004
好比字符串“db”对应的是1008
好比字符串“annie”对应的也是1008
-----保存数据-----
准备一个数组,其长度是2000,而且设定特殊的hashcode算法,使得全部字符串对应的hashcode,都会落在0-1999之间
要存放名字是"gareen"的英雄,就把该英雄和名称组成一个键值对,存放在数组的1001这个位置上
要存放名字是"temoo"的英雄,就把该英雄存放在数组的1004这个位置上
要存放名字是"db"的英雄,就把该英雄存放在数组的1008这个位置上
要存放名字是"annie"的英雄,然而 "annie"的hashcode 1008对应的位置已经有db英雄了,那么就在这里建立一个链表,接在db英雄后面存放annie
-----查找数据-----
好比要查找gareen,首先计算"gareen"的hashcode是1001,根据1001这个下标,到数组中进行定位,(根据数组下标进行定位,是很是快速的) 发现1001这个位置就只有一个英雄,那么该英雄就是gareen.
好比要查找annie,首先计算"annie"的hashcode是1008,根据1008这个下标,到数组中进行定位,发现1008这个位置有两个英雄,那么就对两个英雄的名字进行逐一比较(equals),由于此时须要比较的量就已经少不少了,很快也就能够找出目标英雄
这就是使用hashmap进行查询,很是快原理。
这是一种用空间换时间的思惟方式
步骤 5 : HashSet判断是否重复
HashSet的数据是不能重复的,相同数据不能保存在一块儿,到底如何判断是不是重复的呢?
根据HashSet和HashMap的关系,咱们了解到由于HashSet没有自身的实现,而是里面封装了一个HashMap,因此本质上就是判断HashMap的key是否重复。
再经过上一步的学习,key是否重复,是由两个步骤判断的:
hashcode是否同样
若是hashcode不同,就是在不一样的坑里,必定是不重复的
若是hashcode同样,就是在同一个坑里,还须要进行equals比较
若是equals同样,则是重复数据
若是equals不同,则是不一样数据。
练习: 自定义字符串的hashcode
以下是Java API提供的String的hashcode生成办法;
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
s[0] 表示第一位字符
n表示字符串的长度
本练习并非要求去理解这个算法,而是自定义一个简单的hashcode算法,计算任意字符串的hashcode
由于String类不能被重写,因此咱们经过一个静态方法来返回一个String的hashcode
public static int hashcode(String)
若是字符串长度是0,则返回0。
不然: 获取每一位字符,转换成数字后,相加,最后乘以23
(s[0]+ s[1] + s[2] + s[3]+ s[n-1])*23.
若是值超过了1999,则取2000的余数,保证落在0-1999之间。
若是是负数,则取绝对值。
随机生成长度是2-10的不等的100个字符串,打印用本hashcode获取的值分别是多少
答案:
package collection; public class TestCollection { public static void main(String[] args) { for (int i = 0; i < 100; i++) { int length = (int) (Math.random()*8+2); String str = randomString(length); int hashcode = hashcode(str); System.out.printf("%-11s的自定义hashcode是:%d%n",str,hashcode); } } private static int hashcode(String str) { // TODO Auto-generated method stub if(0==str.length()) return 0; int hashcode = 0; char[]cs= str.toCharArray(); for (int i = 0; i < cs.length; i++) { hashcode +=cs[i]; } hashcode*=23; //取绝对值 hashcode = hashcode<0?0-hashcode:hashcode; //落在0-1999之间 hashcode %=2000; return hashcode; } private static String randomString(int length) { String pool = ""; for (short i = '0'; i <= '9'; i++) { pool += (char) i; } for (short i = 'a'; i <= 'z'; i++) { pool += (char) i; } for (short i = 'A'; i <= 'Z'; i++) { pool += (char) i; } char cs[] = new char[length]; for (int i = 0; i < cs.length; i++) { int index = (int) (Math.random() * pool.length()); cs[i] = pool.charAt(index); } String result = new String(cs); return result; } }