上两篇文章我们实现了自己的ArrayList和LinkedList,也清楚了ArrayList查找方便,修改困难。LinkedList修改方便,查找困难。我们也经常遇到问HashMap和HashSet的异同,其实HashSet的实现就是使用了HashMap只不过它只用到了HashMap中的key值。所以学会了HashMap也就明白了HashSet。
首先我们知道HashMap中是存放键值对的,也就是会有一个key值一个Value值。Key值不能重复,判断标准是equals比较。这也就导致了HashSet中存放的都是无序而不可重复的值,这也是它和ArrayList的区别,ArrayList中存放的是有序可重复的数值。那HashSet的存取速度与ArrayList比较怎么样呢?实际情况是介于ArrayLis和LinkedList之间,因为它的实现是数组+链表的形式。
这我们就要看HashMap中key值得实现,前面说了它是数组+链表实现的,同时根据他的命名也能知道他使用了Hash值。Hash值的引入也是为了更方便查找,相当于字典中的索引一样,每一个对象对应了一个Hash值(不同对象可以有相同的hash值),以该对象hash值根据一定规则处理后的数字作为数组下标存放该值,那么当需要取出该值时,不需要遍历数组中所有的对象,只需要根据该对象的hash值所代表的索引直接定位到该对象即可,大大加快了查询速度。下面以一个图来说明这个问题(图中数据仅举例说明并非真实)
下面描述一下是如何数组+链表存入数据,包含key和value
下面我们就用代码来实现简单的HashMap和HashSet
public class MyMap {
int size;
List[] arr = new LinkedList[1999];
public void put(Object key, Object value){
Entry e = new Entry(key,value);
int a = key.hashCode()%arr.length;
if(arr[a] == null){
List list = new LinkedList();
arr[a]=list;
list.add(e);
}else{
LinkedList list = (LinkedList) arr[a];
for(int i = 0; i < list.size(); i++){
Entry e2 = (Entry) list.get(i);
if(e2.key.equals(key)){
e2.value = value;
return;
}
}
arr[a].add(e);
}
}
public Object get(Object key){
int a = key.hashCode()%arr.length;
if(arr[a] != null){
LinkedList list = (LinkedList) arr[a];
for(int i = 0; i < list.size(); i++){
Entry e = (Entry) list.get(i);
if(e.key.equals(key)){
return e.value;
}
}
}
return null;
}
}
class Entry{
public Entry(Object key, Object value) {
this.key = key;
this.value = value;
}
Object key;
Object value;
}
只需要把HashMap中的key值单独拿出来实现了HashSet
public class MyHashSet {
HashMap map;
private static final Object PRESENT = new Object();
public MyHashSet(){
map = new HashMap();
}
public int size(){
return map.size();
}
public void add(Object o){
map.put(o, PRESENT);
}
}