HashMap原理和TreeMap原理

http://www.importnew.com/7099.html及文章下方评论

http://blog.csdn.net/vking_wang/article/details/14166593超赞

http://blog.csdn.net/ghsau/article/details/16890151容量加载因子

 

HashMap数据结构用数组和链表形式实现:

每个数组中存储的是链表的头元素。每个元素是个entry,包含键和值。

hashmap的get(key)方法得到的是key对应的value,并不是key-value键值对。

 

用了hashing(哈希算法)来查找???(目前来看查找没有完全用哈希算法)

调用put方法存储元素时,会先调用hashcode()方法返回键的hashcode,键的hashcode对数组的长度进行取余运算,得到的值便是桶的位置,比如两个元素的key的hashcode为12和28,数组长度为16,取余的结果都是12,将一起存储在数组下标为12的位置,存储entry实体(不是只存储值哦)。之后调用Map.entry可以获取。

上面hashcode为12和28的key,其对应实体往下标相同的数组中put时怎么put?任何一个元素进来存在数组(数组中存的是最后一个插入的元素),并且该数组的元素有entry属性,其中的next会指向前一个存在数组中的元素。

 

 

HashMap有两个参数影响其性能:初始容量和加载因子。默认初始容量是16还是2的冪次????,加载因子是0.75。容量是哈希表中桶(Entry数组)的数量。初始容量是哈希表创建时的容量,加载因子是哈希表在其容量自动增加前可以达到多满的一种尺度。当哈希表中条目数????超出了加载因子与当前容量的乘机,通过调用rehash方法将容量翻倍。

void addEntry(int paramInt1, K paramK, V paramV, int paramInt2)
{
Entry localEntry = this.table[paramInt2];
this.table[paramInt2] = new Entry(paramInt1, paramK, paramV, localEntry);
if (this.size++ >= this.threshold)
resize(2 * this.table.length);
}

 

覆盖和哈斯算法,16还是2的冪次???????concurrentHashMap和hashtable的区别,set存相同的情况,覆盖equals()需要覆盖hashCode()?

对hashcode()方法进行再哈希的原因:

本身hashcode是一个int型的值,取值范围有40多亿空间。只要哈希函数映射比较均匀松散,一般不会出现哈希碰撞。但是!由于想把各个对象均匀的分不到hashmap的桶中,因此需要对hashcode做取模运算,取模运算保留的是低位区的数字,比如hashmap桶的数量为16时,对hashcode取模保留的是低四位的数字。对于两个对象的hashcode,32位的hashcode一样的情况少,但它们的低四位一样的情况概率挺大的,因此必须对hashcode的低位增加随机性。可以直接对低位使用随机函数,因此采用高低位进行异或运算来增加低位的随机性,以便对象可以在不同的桶中随机分布。

 

java中%表示取余

取余和取模的区别是:在计算商时,取余向正方向舍入得到商,取模则是向负方向舍入得到商。(取模运算必须至少用一个double型做除法,两个int型的数除法只是取整,整数取模的结果有问题)

当除数与被除数的符号相同时,rem和mod的结果是完全相同的;当除数与被除数的符号不相同时,结果不同。
具体说,rem结果的符号与被除数相同;mod结果的符号与除数相同。
 
hashmap中添加元素:
public V put(K key, V value) {
     // 若“key为null”,则将该键值对添加到table[0]中。
         if (key == null) 
            return putForNullKey(value);
     // 若“key不为null”,则计算该key的哈希值,然后将其添加到该哈希值对应的链表中。
         int hash = hash(key.hashCode());
     //搜索指定hash值在对应table中的索引
         int i = indexFor(hash, table.length);
     // 循环遍历Entry数组,若“该key”对应的键值对已经存在,则用新的value取代旧的value。然后退出!
         for (Entry<K,V> e = table[i]; e != null; e = e.next) { 
             Object k;
              if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { //如果key相同则覆盖并返回旧值
                  V oldValue = e.value;
                 e.value = value;
                 e.recordAccess(this);
                 return oldValue;
              }
         }
     //修改次数+1
         modCount++;
     //将key-value添加到table[i]处
     addEntry(hash, key, value, i);
     return null;}


hashset添加元素

public boolean add(E paramE)
{
return this.map.put(paramE, PRESENT) == null;
}

由此知当hashset添加重复元素会返回null(因为hashmap添加key相同的元素时更新value后返回原始value而不是null)

 

hashmap根据key获取元素:

2)get


 public V get(Object key) {

        if (key == null)

            return getForNullKey();

        int hash = hash(key.hashCode());

        //先定位到数组元素,再遍历该元素处的链表(hashcode无法直接定位到元素的地址)

        for (Entry<K,V> e = table[indexFor(hash, table.length)];

             e != null;

             e = e.next) {

            Object k;

            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))

                return e.value;

        }

        return null;

}
 
hash():
static final int hash(Object key) {
int h;

return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

}
hashcode右移16位左边补0后与原hashcode异或运算增加低位随机性。 


TreeMap
TreeMap基于红黑树实现
主要用于存入元素的时候对元素进行自动排序,迭代输出的时候就按排序顺序输出。
TreeMap中key不能为null
http://www.cnblogs.com/wzyxidian/p/5204879.html
posted @ 2017-09-11 16:46  新生的小心情  阅读(385)  评论(0编辑  收藏  举报