Java HashMap简介
来源:互联网 发布:淘宝代做课程设计 编辑:程序博客网 时间:2024/05/22 14:40
http://www.cnblogs.com/chengxiao/p/6059914.html
http://blog.csdn.net/vking_wang/article/details/14166593
Java中的存储结构无外乎两种:一种是顺序存储结构,也就是申请一块连续的内存空间:以数组的形式显示。像一般的顺序栈,顺序队列就是这样。另外一种则是链式存储结构,链表,链式栈,链式队列,二叉树(一般不用顺序存储结构实现二叉树,因为极大的浪费空间)。
接下来我们来讨论一下顺序存储和链式存储的优缺点。
顺序存储 ——优点:当知道或者能够估计使用的数据的数量时,可以使用顺序存储,因为存取方便,时间复杂度为 O(1)。
缺点:删除上会极大的不方便,因为需要移动位置,从而影响性能
链式存储 ——优点:不需要事先知道数据量,可以自动申请空间,删除上会方便,因为不需要移动位置,只需改变引用 即可。
缺点:数据的查询会不方便,因为链式存储的数据结构一般都是通过头节点进行遍历来查询的,时间复杂度即便通过一些经典算法也会比较大。
但是,HashMap这一数据结构实现了顺序存储和链式存储的结合,通过键值对(key,value)的方式实现了数据的快速保存和读取。
第一步:HashMap的保存和读取实际上使用的是对象数组Entry(HashMap中的静态内部类)进行存储,接着通过构造函数实现table的初始化。
static class MEntry<K,V>{
int hash; //对key进行hash()函数后得到的值
K key;
V value;
MEntry<K, V> nextEntry;//链表结构
public MEntry() {
}
public MEntry(int index, K key, V value) {
super();
this.hash = index;
this.key = key;
this.value = value;
}
}
第二步:通过hash函数和indexfor函数得到key的下标,如果下标的数组为空,直接插入。如果不为空,遍历该下标数组,将相同的key覆盖,不相同的利用链表的插入插到头节点。
第三步:在插入数据时候判断size<=threshold,如果size>threshold,则需要进行扩容。
由于分析的数据量太大,本人讲的可能难以理解。以下是本人实现hashmap的源码(不完整):
package test.map;
public class HashMap<K, V> {
static class MEntry<K,V>{
int hash; //对key进行hash()函数后得到的值
K key;
V value;
MEntry<K, V> nextEntry;//链表结构
public MEntry() {
}
public MEntry(int index, K key, V value) {
super();
this.hash = index;
this.key = key;
this.value = value;
}
}
final static int DEFAULT_CAPACITY=16; //默认值,用户没有指定则为16
final static float DEFAULT_LOAD_FACTOR=0.75f;
static final int MAXIMUM_CAPACITY = 1 << 30;
public MEntry<K, V>[] table; //hashmap的内部实际结构
int capacity; //hashmap数组的长度
int size; //hashmap的长度,不能超过阙值
int threshold; //hashmap的阙值 =capacity*loadFactor
float loadFactor; //hashmap的装载因子=size/capacity
public HashMap(int capacity,float loadFactor){ //初始化默认hashmap
if (capacity < 0)
throw new IllegalArgumentException("错误的capacity: " +capacity);
if (capacity > MAXIMUM_CAPACITY)
capacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("错误的装载因子: " + loadFactor);
this.loadFactor = loadFactor;
this.capacity=capacity;
/*this.threshold=(int)(this.capacity*this.loadFactor);
不在这里设置上一句的原因是需要在初始化table时将capacity赋值为2的幂*/
}
public HashMap(){
this(DEFAULT_CAPACITY,DEFAULT_LOAD_FACTOR);
}
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
/**
* hash函数,将key转化为数组下标
* @return
*/
private int hash(Object key){
int h=0;
h ^= key.hashCode(); //调用自身的hashcode方法(如:String则调用String.class的hashcode()方法)
h ^= (h >>> 20) ^ (h >>> 12); //按位的异或
return h ^ (h >>> 7) ^ (h >>> 4);
}
private static int roundUpToPowerOf2(int number) {
// assert number >= 0 : "number must be non-negative";
int rounded = number >= MAXIMUM_CAPACITY
? MAXIMUM_CAPACITY
: (rounded = Integer.highestOneBit(number)) != 0
? (Integer.bitCount(number) > 1) ? rounded << 1 : rounded
: 1;
return rounded;
}
/**
* 通过构造函数得到的capacity初始化table,长度必须是比capacity最接近的2的幂
* @param capacaity
*/
private void initTable(int capacaity){
int capacity = roundUpToPowerOf2(capacaity);
threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
table = new MEntry[capacity];
}
private void addEntry(int hash,K key,V value,int index){
table[index]=new MEntry<K,V>(hash,key,value);
table[index].nextEntry=null;
}
int indexFor(int h, int length) {
return h & (length-1);
}
private void resize(int newCapacity){
MEntry[] oldTable = table; //将table地址复制给新的引用变量
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {//如果旧的table长度已经到达最大,将不再扩容
threshold = Integer.MAX_VALUE;
return;
}
MEntry[] newTable = new MEntry[newCapacity]; //创建新的MEntry对象数组,长度为之前的一倍
transfer(newTable); //将旧数组的内容copy到新的数组
table = newTable;
threshold = (int)(newCapacity * loadFactor);
}
void transfer(MEntry[] newTable) {
MEntry[] src = table;
int newCapacity = newTable.length;
for (int j = 0; j < src.length; j++) {
MEntry<K,V> e = src[j];
if (e != null) {
src[j] = null;
do {
MEntry<K,V> next = e.nextEntry;
//重新计算index
int i = indexFor(e.hash, newCapacity);
e.nextEntry = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
}
}
}
public void put(K key,V value){
if(table==null){
System.out.println("当前table为空,正在初始化数组");
initTable(this.capacity); //如果table为空,则初始化table
}
int hash=hash(key); //获取hash函数获取hash值
int index=indexFor(hash, table.length);//通过与运算得到判断冲突的数组下标
if(table[index]==null){ //说明当前该下标数组为空,直接插入
if(size==threshold){ //如果当前size到达阙值,需要扩容
resize(2 * table.length);
index=indexFor(hash, table.length);//由于改变了table的长度,需要重新寻找下标
}
System.out.println("下标"+index+"数组为空,插入Key:"+key+" value:"+value);
addEntry(hash, key, value, index);
size++;
}
else{ //说明当前带下标数组存在链表
for(MEntry<K, V> e=table[index];e!=null;e=e.nextEntry){ //说明存在链表
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { //判断是否存在相同的key
System.out.println("下标"+index+"存在冲突key相同,将覆盖");
V oldValue = e.value;
e.value = value;
}
else{ //不存在相同的key
if(size==threshold){ //如果当前size到达阙值,需要扩容
resize(2 * table.length);
index=indexFor(hash, table.length);//由于改变了table的长度,需要重新寻找下标
}
System.out.println("下标"+index+"存在冲突key不同,将插入");
MEntry<K,V> newEntry= new MEntry<>(hash, key, value);
newEntry.nextEntry=table[index];
table[index]=newEntry;
size++;
}
}
}
}
public V get(Object key){
int hash=hash(key);
int index=indexFor(hash, table.length);//通过与运算得到判断冲突的数组下标
V value=null;
MEntry<K,V> mEntry=table[index];
while(mEntry!=null){
if(key==mEntry.key||key.equals(mEntry.key)){
return value=mEntry.value;
}
else mEntry=mEntry.nextEntry;
}
return value;
}
public int getSize(){
return this.size;
}
}
- Java HashMap简介
- Java 里的HashMap(HashTable) 简介.
- HashMap简介
- Hashmap简介
- HashMap简介
- HashMap简介
- HashMap简介
- HashMap简介
- HashMap,LinkedHashMap,TreeMap简介
- HashMap的使用简介
- HashMap简介与应用
- hashmap原理简介
- java hashMap
- Java HashMap
- java---hashmap
- java hashmap
- Java HashMap
- JAVA-HASHMAP
- LIBSVM的简易入门
- 装了新版本的JDK 打开CMD 发现还是原来的版本
- 3. Longest Substring Without Repeating Characters
- C语言青葱之路-指针练习-输入整型数组,用指针输出
- CentOS安装Maven
- Java HashMap简介
- 有趣的汉语:同音文(一):《季姬击鸡记》
- 构建高可用ZooKeeper集群
- c++基础知识(4)
- Mysql常用命令详解
- c++8
- 整数排序
- 编辑神器 Emmet
- SPPNet:Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition