`
bearsorry
  • 浏览: 92969 次
  • 性别: Icon_minigender_2
  • 来自: 湖南
社区版块
存档分类
最新评论

用java分析hash表结构及性能(二)

 
阅读更多

七,用代码来验证自己写的hash表以及性能分析(之前的rehash方法写错了,现在更正过来了!)

package cn.java1118;
/**
 * 自己写的hashmap类
 * @author acer
 *
 * @param <K>:关键字类
 * @param <V>:数据域类
 */
public class MyHashMap04<K,V> {

	//存放键值对的数组
	private Entry<K,V>[] hashTable;
	//当前容量的大小
	private int numberOfEntries;
	//装载因子
	private static final double MAX_LOAD_FACTOR=0.75;
	//集合初始化的一个大小
	static final int DEFAULT_INITIAL_CAPACITY = 16;
	
	public MyHashMap04(){
		this(DEFAULT_INITIAL_CAPACITY);
	}
	
	public MyHashMap04(int tablesize){
		//实例化数组的大小
		hashTable = new Entry[tablesize];
		//初始化的时候hash表里面什么都木有
		this.numberOfEntries=0;
	}
	/**
	 * 补充哈希函数
	 * @param h:每一个对象都有的hashcode
	 * @return:另一种hashcode
	 */
	static int hash(int h) {
		//直接copyJDK自带的这个算法
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }
	
	/**
	 * 根据key取得value值
	 * @param key:键
	 * @return:键所对应的值
	 */
	public V getValue(K key){
		
		//要返回的值
		V result = null;
		//得到要key在数组的下标
		int hash = hash(key.hashCode());
		int index = indexFor(hash, hashTable.length);
		//对键值对链表进行遍历
		for (Entry<K,V> e = hashTable[index]; e != null; e = e.next) {
	            Object k;
	            if (e.hash == hash && ((k = e.key) == key || key.equals(k))){
	                return e.value;
	            }
	        }
		return result;
	}
	/**
	 * 添加元素
	 * @param key
	 * @param value
	 * @return:添加成功则为null,否则返回之前的值
	 */
	public V add(K key,V value){
		//键值为null时的处理方法
		if (key == null)
            return putForNullKey(value);
		//返回值变量
		V oldValue;
		
		//得到这个键在数组中的下标
		int hash = hash(key.hashCode());
		int index = indexFor(hash, hashTable.length);
		//看是否存在一样的键和hashcode
		for (Entry<K,V> e = hashTable[index]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            	//存在这样的键值对了
                oldValue = e.value;
                e.value = value;
               
                return oldValue;
            }
        }
		//插入一个键值对的时候当前的容量会+1
		numberOfEntries++;
		//进行插入
		addEntry(hash, key, value, index);
		return null;
	}
	/**
	 * 当插入的键位null时的处理
	 * @param value:值
	 * @return:插入成功则返回null,不成功则返回这个键原来所对应的值
	 */
	private V putForNullKey(V value) {
        for (Entry<K,V> e = hashTable[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                return oldValue;
            }
        }
        numberOfEntries++;
        addEntry(0, null, value, 0);
        return null;
    }
	/**
	 * 插入键值对链表
	 * @param hash:hashcode
	 * @param key:键
	 * @param value:值
	 * @param bucketIndex:数组上的下标
	 */
	void addEntry(int hash, K key, V value, int bucketIndex) {
		//将原来的保留
		Entry<K,V> e = hashTable[bucketIndex];
		//在原来的基础上添加
		hashTable[bucketIndex] = new Entry<K,V>(hash, key, value, e);
		if(!isHashTableTooFull()){
			//看是否超出其装载因子
			rehash();
		}
	    }
	
	//检验hash表的装载因子是否大于默认值
	private boolean isHashTableTooFull() {
		//装载因子是有大小限制的
		if(numberOfEntries/hashTable.length>=MAX_LOAD_FACTOR){
			return false;
		}
		return true;
	}

	/**
	 * 再hash的方法
	 */
	private void rehash() {
		//保留原hash表
		Entry<K, V>[] oldHashTable = hashTable;
		int oldSize = hashTable.length;
		//扩大为原来的两倍
		int newSize = oldSize*2;
		hashTable = new Entry[newSize];
		numberOfEntries=0;
		
		//还要遍历原hash表,即将原来放进来的数据重新插入到新的hash表中
		for(int i=0;i<oldHashTable.length;i++){
			Entry<K, V> e = oldHashTable[i];
			if(e!=null){
				do{
					Entry<K, V> next = e.next;
				int index = indexFor(hash(e.hash), newSize);
			addEntry(e.hash, e.key, e.value, index);
			e=next;
				}while(e!=null);
				
			}
		}
	}
	/**
	 * 删除指定key的键值对
	 * @param key:键
	 * @return
	 */
	 public V remove(Object key) {
	        Entry<K,V> e = removeEntryForKey(key);
	        return (e == null ? null : e.value);
	    }
	 /**
	  * 跟查找的过程差不多
	  * @param key
	  * @return
	  */
	 final Entry<K,V> removeEntryForKey(Object key) {
	        int hash = (key == null) ? 0 : hash(key.hashCode());
	        int i = indexFor(hash, hashTable.length);
	        Entry<K,V> prev = hashTable[i];
	        Entry<K,V> e = prev;

	        while (e != null) {
	            Entry<K,V> next = e.next;
	            Object k;
	            if (e.hash == hash &&
	                ((k = e.key) == key || (key != null && key.equals(k)))) {
	                numberOfEntries--;
	                if (prev == e)
	                    hashTable[i] = next;
	                else
	                    prev.next = next;
	                return e;
	            }
	            prev = e;
	            e = next;
	        }

	        return e;
	    }
	 
	/**
	 * 得到在数组中的下标位置
	 * @param h:hashcode
	 * @param length:hash表的长度
	 * @return:下标位置
	 */
	static int indexFor(int h, int length) {
        return h & (length-1);
    }
	/**
	 * 实例化一个装键值对链表
	 * @author acer
	 *
	 * @param <K>
	 * @param <V>
	 */
	private class Entry<K,V>{
		private K key;
		private V value;
		//每一个对象都有一个hashcode,是唯一的,在map中不能存放hashcode一样的对象
		private int hash;
		//下一个键值对节点
		private Entry<K,V> next;
		
		private Entry(int hash,K key,V value,Entry<K,V>next){
			this.key = key;
			this.value = value;
			this.next = next;
			this.hash = hash;
		}

		public K getKey() {
			return key;
		}

		public V getValue() {
			return value;
		}
		//重写equals方法
		 public final boolean equals(Object o) {
	            if (!(o instanceof Entry))
	                return false;
	            Entry e = (Entry)o;
	            //得到两个比较的key值
	            Object k1 = getKey();
	            Object k2 = e.getKey();
	            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
	            	//得到两个比较的value值
	                Object v1 = getValue();
	                Object v2 = e.getValue();
	                if (v1 == v2 || (v1 != null && v1.equals(v2)))
	                    return true;
	            }
	            return false;
	        }
	}
}

 

  

性能分析代码:

package cn.java1118;

import java.util.HashMap;

public class Test1 {  
	  
    public static void main(String[] args) {  
    	//自己的hashmap
    	MyHashMap04<String, String> mm = new MyHashMap04<String, String>();   
        Long aBeginTime=System.currentTimeMillis();  
        for(int i=0;i<1000000;i++){  
        mm.add(""+i, ""+i*100);  
        }  
        Long aEndTime=System.currentTimeMillis();//记录EndTime  
        System.out.println("insert time-->"+(aEndTime-aBeginTime));  
          
        Long lBeginTime=System.currentTimeMillis();//记录BeginTime  
        mm.getValue(""+100000);  
        Long lEndTime=System.currentTimeMillis();//记录EndTime  
        System.out.println("seach time--->"+(lEndTime-lBeginTime));
        
        Long rBeginTime=System.currentTimeMillis();//记录BeginTime  
        mm.remove(""+10000);  
        Long rEndTime=System.currentTimeMillis();//记录EndTime  
        System.out.println("remove time--->"+(rEndTime-rBeginTime));
    	
    	//系统的hashmap
//    	HashMap<String, String> mm = new HashMap<String, String>();   
//        Long aBeginTime=System.currentTimeMillis();//记录BeginTime  
//        for(int i=0;i<1000000;i++){  
//        mm.put(""+i, ""+i*100);  
//        }  
//        Long aEndTime=System.currentTimeMillis();//记录EndTime  
//        System.out.println("insert time-->"+(aEndTime-aBeginTime));  
//          
//        Long lBeginTime=System.currentTimeMillis();//记录BeginTime  
//        mm.get(""+100000);  
//        Long lEndTime=System.currentTimeMillis();//记录EndTime  
//        System.out.println("seach time--->"+(lEndTime-lBeginTime));
//        
//        Long rBeginTime=System.currentTimeMillis();//记录BeginTime  
//        mm.remove(""+10000);  
//        Long rEndTime=System.currentTimeMillis();//记录EndTime  
//        System.out.println("remove time--->"+(rEndTime-rBeginTime));
    }  
}  
 

  

 


 

 

系统的测试结果:

insert time-->2148
seach time--->0

我的测试结果:

insert time-->2236
seach time--->0
remove time--->0

看,查找的速度为0呃,插入也只要2秒多。。。

 

还有一个是存储空间的测试:

 

 

 

 

 

<!--EndFragment-->

分享到:
评论

相关推荐

    Java思维导图xmind文件+导出图片

    redis使用常见问题及性能优化思路 redis高可用及高并发实战 缓存击穿、缓存雪崩预防策略 Redis批量查询优化 Redis高性能集群之Twemproxy of Redis 数据存储 MongoDB NOSQL简介及MongoDB支持的数据类型分析 ...

    数据结构(C语言版)\Java数据结构和算

    1.5 性能分析 1.6 性能度量 1.7 参考文献和选读材料 第2章 数组和结构 2.1 数组 2.2 数组的动态存储分配 2.3 结构体和联合体 2.4 多项式 2.5 稀松矩阵 2.6 多维数组的表示 2.7 字符串 2.8 参考文献和选读...

    JAVA上百实例源码以及开源项目源代码

     用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历,...

    JAVA上百实例源码以及开源项目

     用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历,...

    JAVA面试题最全集

    一、Java基础知识 1.Java有那些基本数据类型,String是不是基本数据类型,他们有何区别。 2.字符串的操作: 写一个方法,实现字符串的反转,如:输入abc,输出cba 写一个方法,实现字符串的替换,如:输入...

    【白雪红叶】JAVA学习技术栈梳理思维导图.xmind

    关于java程序员发展需要学习的路线整理集合 技术 应用技术 计算机基础知识 cpu mem disk net 线程,进程 第三方库 poi Jsoup zxing Gson 数据结构 树 栈 链表 队列 图 操作系统 linux 代码控制...

    数据结构:八大数据结构分析.pdf

    数据结构:⼋⼤数据结构分析 数据结构分类 数据结构是指相互之间存在着⼀种或... 散列数据结构的性能取决于以下三个因素: 哈希函数 哈希表的⼤⼩ 碰撞处理⽅法 哈希表在应⽤中也是⽐较常见的,就如Java中有些集合类

    java 面试题 总结

    Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异。 12、final, finally, finalize的区别。  final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。 ...

    Java面试宝典-经典

    5、说明生活中遇到的二叉树,用java实现二叉树 66 6、从类似如下的文本文件中读取出所有的姓名,并打印出重复的姓名和重复的次数,并按重复次数排序: 71 7、写一个Singleton出来。 75 8、递归算法题1 77 9、递归...

    Java面试宝典2010版

    5、说明生活中遇到的二叉树,用java实现二叉树 66 6、从类似如下的文本文件中读取出所有的姓名,并打印出重复的姓名和重复的次数,并按重复次数排序: 71 7、写一个Singleton出来。 75 8、递归算法题1 77 9、递归...

    java面试题大全(2012版)

    4、编程用JAVA解析XML的方式. 115 5、XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式? 117 七. 流行的框架与新技术 117 1、谈谈你对Struts的理解。 117 2、谈谈你对Hibernate的理解。 118 ...

    最新Java面试宝典pdf版

    5、说明生活中遇到的二叉树,用java实现二叉树 66 6、从类似如下的文本文件中读取出所有的姓名,并打印出重复的姓名和重复的次数,并按重复次数排序: 71 7、写一个Singleton出来。 75 8、递归算法题1 77 9、递归...

    java面试宝典2012

    各种java面试题集,面试前必备哦, 1. Java基础部分 7 1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 8 2、Java有没有goto? 8 3、说说&和&&的区别。 8 4、在JAVA中如何跳出当前的多重嵌套...

    Java面试笔试资料大全

    5、说明生活中遇到的二叉树,用java实现二叉树 66 6、从类似如下的文本文件中读取出所有的姓名,并打印出重复的姓名和重复的次数,并按重复次数排序: 71 7、写一个Singleton出来。 75 8、递归算法题1 77 9、递归...

    JAVA面试宝典2010

    5、说明生活中遇到的二叉树,用java实现二叉树 66 6、从类似如下的文本文件中读取出所有的姓名,并打印出重复的姓名和重复的次数,并按重复次数排序: 71 7、写一个Singleton出来。 75 8、递归算法题1 77 9、递归...

    Java面试宝典2012新版

    4、编程用JAVA解析XML的方式. 115 5、XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式? 117 七. 流行的框架与新技术 117 1、谈谈你对Struts的理解。 117 2、谈谈你对Hibernate的理解。 118 ...

    Java面试宝典2012版

    4、编程用JAVA解析XML的方式. 115 5、XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式? 117 七. 流行的框架与新技术 117 1、谈谈你对Struts的理解。 117 2、谈谈你对Hibernate的理解。 ...

Global site tag (gtag.js) - Google Analytics