散列和散列码
※正确的equals方法应该满足的的条件:
①自反性:x.equals(x) 一定返回true;
②对称性:y.euqlas(x)为true,那么x.equals(y)一定为true;
③传递性:x.equals(y)为true,y.euqlas(z)为true,则z.equals(x)为true;
④一致性:如果x,y中用于等价比较的信息没有变化,那么无论调用y.euqlas(x)多少次,结果都是一致的;
⑤对任何不是null的x,x.equals(null)一定为false;
1、在查询方式里,
线性查询是最慢的查询方式;
2、散列的价值在于速度,它使用一组数组(Java中储存查询速度最快的数据结构)来储存键的信息(并非键本身);
数组本身不保存键本身,而是通过键本身生成一个编码,将其作为数组下标,该编码就是散列码,由键的hashCode(散列函数)产生;
数组保存的一个记录键的list,当在一个数组中的散列码发生冲突时,有外部链接解决冲突,并加入同一个list中;
3、在散列结构里查找一个键:
①计算该键的散列码,使用该散列码查询数组;
②对该数组下标的list使用根据equals进行线性查询;
4、散列表中的一些术语:
①容量:表中的桶buckets位数;
②初始容量:表在创建时拥有的桶位数,HashMap和HashSet都允许指定初始容量的构造器;
③尺寸:表中当前储存的位数;
④负载因子:尺寸/容量,空表负载为0,满表负载为1.0,负载轻产生的冲突可能性小,有利于插入和查询,但是会减慢使用迭代器遍历元素,默认的负载因子为0.75;
⑤再散列:当负载达到负载因子的水平时,容器会自动增加容量(双倍增加);
5、散列容器的模型:
6、hashCode的实现:
7、HashMap的实现和key元素实现散列码
<span style="color:#000000;">import java.util.*;
public class SimpleHashMap<K,V> extends AbstractMap<K,V>{
static final int SIZE = 997; //默认bucket数量;
@SuppressWarnings("unchecked")
LinkedList<MapEntry<K,V>>[] buckets = new LinkedList[SIZE];
//放置映射关系,返回原先的映射Value;
public V put (K key, V value){
int index = Math.abs(key.hashCode()) % SIZE;
if(buckets[index] == null)
buckets[index] = new LinkedList<MapEntry<K, V>>();
V oldValue = null;
LinkedList<MapEntry<K,V>> bucket = buckets[index];
MapEntry<K, V> pair = new MapEntry<K,V>(key,value);
ListIterator<MapEntry<K,V>> iter = bucket.listIterator();
//检查重复key,更新value
boolean found = false;
while(iter.hasNext()){
MapEntry<K,V> tempPair = iter.next();
if(tempPair.getKey().equals(key)){
oldValue = tempPair.getValue();
iter.set(pair);
found = true;
break;
}
}
if(!found)
buckets[index].add(pair);
return oldValue;
}
public V get(Object key){
int index = Math.abs(key.hashCode()) % SIZE;
if(buckets[index] == null)
return null;
for(MapEntry<K,V> pair : buckets[index]){
if(pair.getKey().equals(key))
return pair.getValue();
}
return null;
}
@Override
public Set<Map.Entry<K, V>> entrySet() {
Set<Map.Entry<K, V>> set = new HashSet<Map.Entry<K,V>>();
for(LinkedList<MapEntry<K,V>> bucket : buckets){
if(bucket == null)
continue;
for(MapEntry<K,V> pair : bucket)
set.add(pair);
}
return set;
}
class MapEntry<K,V> implements Map.Entry<K, V>{
K key;
V value;
public MapEntry(K key,V value){
this.key = key;
this.value = value;
}
@Override
public K getKey(){
return this.key;
}
@Override
public V getValue() {
return this.value;
}
@Override
public V setValue(V value) {
return this.value = value;
}
}
/*实现可以引用在在HashMap对象的key对象,该对象必须实现hashCode方法*/
import java.util.*;
public class CountString {
private static List<String> created = new ArrayList<String>();
//用于记录一次程序运行创建的所哟 String s实例,当s发生重复时,生成唯一的id,以产生唯一的散列值;
private String s ; //用于记录内容的数据域
private int id = 0; //记录相同String的CountString对象的编号
public CountString(String str){
this.s = str;
created.add(s);
for(String e : created){
if(e.equals(s))
this.id++;
}
}
public int hashCode(){
int result = 17; //设置初始偏移量
result = 37*result + s.hashCode(); //37稀释值
result = 37*result + id; //进行第二次稀释,放置ID值破坏s.hasCode;
return result;
}
public boolean equals(Object o){
return o instanceof CountString && s.equals(((CountString)o).getS())
&& id == ((CountString)o).getId();
}
public String getS(){
return this.s;
}
public int getId(){
return this.getId();
}
public String toString(){
return "String:"+s+" id:"+id+" hashCode: "+hashCode();
}
}
</span>