`
981875739
  • 浏览: 7683 次
  • 性别: Icon_minigender_2
  • 来自: 长沙
社区版块
存档分类
最新评论

MyHash实现

 
阅读更多

经过一段时间的研究学习,对于Hash有了更深一步的了解和认识,下面谈谈一些基本概念及自己设计的一个MyHash的实现。


1、基本概念:
Hash,一般翻译做“散列”,也有直接音译为“哈希”。
哈希就是把任意长度的输入通过散列算法,变换成固定长度的输出,该输出就是散列值。

Hash主要用于信息安全领域中加密算法,把一些不同长度的信息转化成杂乱的128位编,这些编码值叫哈希值也可以说哈希就是找到一种数据内容和数据存放地址之间的映射关系。
哈希表就是一种根据关键码值直接进行访问的数据结构。
 
2、哈希表的优缺点:
那么为什么使用哈希表呢?它一定有特定的优点我们才会使用它。看看这个图表,相信大家就了解了吧~~


数组具有查找迅速但是对其进行插入删除操作较困难的特点,而链表容易插入删除但查找困难。。。是否有一种数据结构能够将两者的优点集合呢?哈希表就是一个两全其美的选择~~他是直接根据key值找到相应的存储位置,对其进行访问,插入删除操作类似于链表的相关操作。哈希表是基于快速存取的角度设计的,它的优点非常明显,存取速度能达到常量级O(1)
当然它也有一定的缺点:
1、使元素丧失了有序性
2、元素不能够紧密的排列,需要足够大的空间
3、两个或多个不同项被散列到同一位置是不可避免的 ——冲突
  【冲突:对不同的关键字可能得到同一散列地址 key1key2,而f(key1)=f(key2)

3、常用的构造构造哈希函数的方法:
v1.直接寻址法
v2.数字分析法
v3.平方取中法
v4.叠加法
v5.随机数法
v6.除留余数法
比较常用的是除留余数法,下面详细介绍一下此方法:
取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址 。
H(key) = key MOD p     (p<=m)  
例如: 给定一组关键字为:          12, 39, 18, 24, 33, 21 
         H(key) = key MOD 9     3    3    0    6    6   3  
这里对P要有什么限制条件呢?                                         
12, 39, 18, 24, 33, 21
若取 p=9, 则他们对应的哈希函数值将为: 3, 3, 0, 6, 6, 3 
若取 P=18,则他们对应的哈希函数值将为12,3,0,6,15,3
若取p=24,则他们将对应的哈希函数值将为: 12,15,18,0,9,21 
一般结论:选取的P较小,冲突的可能性较大

4、解决冲突的方法:
1、拉链法:即构造成数组链表的形式
2、在哈希法:设计两种甚至多种哈希函数
3、开放地址法:线性/二次/随机探测再散列
4、建域法:建立一个公共溢出区存储发生冲突的记录

5、下面是一个我实现的MyHash:解决冲突是采用的第一种方法
package MyHash2;

import java.util.Collection;
import java.util.Iterator;

/**
 * MyHash类
 * @author Administrator
 *
 * @param <T>
 */
public class MyHash<T>implements Collection<T>{
	private Entry[] table;
	private int hashTableSize;
	private int Capacity=16;//初始大小
	private float LoadFactor= 0.75f;//默认装载因子
	private int tableThreshold;//最大承载大小
	private int modCount=0;
	
	/**
	 * 结点类
	 * @author Administrator
	 *
	 * @param <T>
	 */
	private static class Entry<T>{
		T value;//数值
		int hashvalue;//hash值
		Entry<T> next;//指针
		public Entry(T value,int hashvalue,Entry<T> next){
			this.value=value;
			this.hashvalue=hashvalue;
			this.next=next;
		}		
	}
	
	/**
	 * 构造函数
	 */
	public MyHash(){
		table=new Entry[Capacity];
		hashTableSize=0;
		tableThreshold =(int)(table.length * LoadFactor);
	}

	/**
	 * 添加数据
	 */
	public boolean add(T item){
		int hashvalue=item.hashCode();//计算hashvalue
		int index=hashvalue%table.length;//计算下标
		//System.out.println("item.hashCode()="+hashvalue+"   table.length="+table.length+"    index="+index);		
		Entry<T> entry;
		entry= table[index];
		//不为空,则查找该数据是否已存在;为空则加入
		while(entry!=null){
			if(entry.value.equals(item)){
				System.out.println("该数据已经存在");
				return false;
			}
			entry=entry.next;
		}
		modCount++;
		entry =new Entry<T>(item,hashvalue,(Entry<T>) table[index]);
		table[index]=entry;
		hashTableSize++;
		//检查hash表是否已超过最大承载量
		if(hashTableSize>tableThreshold){
			int newTableSize=2 * table.length + 1;
			rehashing(newTableSize);
		}
//		System.out.println("添加数据"+item+"成功");
		return true;
	}
	
	/**
	 * 移除数据
	 */
	public boolean remove(Object item){
		int index =item.hashCode()%table.length;
		Entry<T> current;
		Entry<T> previous=null;
		current=table[index];
		//对应下标的数组位置有数据
		while(current!=null){
			//找到要删除的数据
			if(current.value.equals(item)){
				modCount++;
				//该数据不是链表的第一个数据,则将前一个数据的指针指向下一个数据
				if(previous!=null){
					previous.next=current.next;
				}else{//该数据是链表的第一个数据,则将下一个数据挪到当前下标处
					table[index]=current.next;
				}
				hashTableSize--;
				System.out.println("删除了数据:"+current.value+"  index为"+index);
				return true;
			}else{//向下继续找要删除的数据
				previous=current;
				current=current.next;
			}
		}
		return false;
	}
	
	/**
	 * 查找某数据
	 * @param item
	 * @return
	 */
	public boolean find(Object item){
		int index=item.hashCode()%table.length;//计算出下标
		Entry<T> entry=table[index];
		//对数组下标下的链表进行查找
		while(entry!=null){			
			//与对应下标内的数据进行equals比较
			if(entry.value.equals(item)){
				System.out.println("查找到数据:"+entry.value+"  index为"+index);
				return true;
			}			
			entry=entry.next;
		}
		System.out.println("查找失败,数据不存在");
		return false;
	}
	
	/**
	 * 清除所有数据
	 */
	public void clear(){
		int len=table.length;
		//遍历———清空数据
		for(int i=0;i < len; i++){
			table[i] = null;  
		    modCount++;  
		    hashTableSize = 0;  
        }
	}

	/**
	 * rehash方法
	 * @param rehashSize
	 */
	public void rehashing(int newTableSize){
		System.out.println("Hash重构");
		Entry[] newTable =new Entry[newTableSize];//新HashTable
		Entry[] oldTable = table;//原HashTable
		int index;
		Entry entry;
		//循环,将原HashTable内的数据重新计算地址,存入新HashTable
		for(int i=0;i<table.length;i++){
			entry=table[i];
			if(entry!=null){
				//先将该位置的原数据清除,设为NUll
				table[i]=null;
				//向新HashTabele中添加该数据
				while(entry!=null){
					Entry newEntry=entry.next;
					index=entry.hashvalue%newTableSize;
					entry.next = newTable[index];  
					newTable[index] = entry;  
                    entry = newEntry;  
				}
			}
		}
		table=newTable;
		//重新设置装载量大小
		tableThreshold = (int) (table.length * LoadFactor);  
		//将原HashTable清空
		oldTable = null;  
	}
	
//	/**
//	 * 计算HashCode的方法
//	 * @return
//	 */
//	public int hashcode(Object item){
//		int index = item.hashCode()%table.length;
//		return index;
//	}
	@Override
	public int size() {
		// TODO Auto-generated method stub
		return hashTableSize;  
	}
	@Override
	public boolean isEmpty() {
		// TODO Auto-generated method stub
		return hashTableSize == 0;  
	}
	@Override
	public boolean contains(Object o) {
		// TODO Auto-generated method stub
		return false;
	}
	@Override
	public Iterator<T> iterator() {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public Object[] toArray() {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public <T> T[] toArray(T[] a) {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public boolean containsAll(Collection<?> c) {
		// TODO Auto-generated method stub
		return false;
	}
	@Override
	public boolean addAll(Collection<? extends T> c) {
		// TODO Auto-generated method stub
		return false;
	}
	@Override
	public boolean removeAll(Collection<?> c) {
		// TODO Auto-generated method stub
		return false;
	}
	@Override
	public boolean retainAll(Collection<?> c) {
		// TODO Auto-generated method stub
		return false;
	}
	
	
}
 
Test测试类:
加入150万个数据(打印Size、添加数据所需的时间)—>查找一个特定数据(打印该数据、数据所在数组位置的下标、查找时间)—>删除一个数据(打印Size)—>再次查找该数据(查找失败)—>清空全部数据

Hash重构十七次


添加数据时间为:1906
此时Size为1500000
查找到数据:100000  index为290089
查找数据时间为:0
删除了数据:100000  index为290089
此时Size为1499999
查找失败,数据不存在
查找到数据:100000  index为290089
清除全部数据了,此时Size为0


发现多次执行同一程序,添加数据的时间与之前相比会少。。。
  • 大小: 11.6 KB
  • 大小: 27.2 KB
分享到:
评论

相关推荐

    MyHash64_1.4.7.exe

    MyHash64_1.4.7.exe是一个计算文件SHA1、MD5值的工具,可以对比两个文件的完整性

    MyHash-master.zip

    查看对比md5,sha1等

    MyHash_1.4_校验工具

    一款采用并行计算,充分利用多核CPU性能,快速计算文件哈希值的工具。这款小巧实用的工具,原生单执行文件,采用UPX压缩后体积才几百KB,支持MD5、SHA1、CRC32、SHA256、SHA512等算法;支持哈希值比较、支持多个文件...

    MyHash 1.4.7.0

    一款采用并行计算,充分利用多核CPU性能,快速计算文件哈希值的工具。单文件,整合32位和64位可执行程序。作者drag0n发布的最终版,验证文件的首选。 功能特点: 1、只支持常用的CRC32、MD5、SHA1、SHA256、SHA512...

    文件校验工具 MyHash v1.4.6.7z

    MyHash是一款由drag0n编写的校验工具,采用并行计算,充分利用多核CPU性能,快速计算文件哈希值的工具。这款小巧实用的工具,原生单执行文件,采用UPX压缩后体积才几百KB,支持MD5、SHA1、CRC32、SHA256、SHA512等...

    一个c++实现的哈希表类

    程序的具体实现如下:本程序是用模板类myhash来实现,包括protected和public属性成员。其中protected成员有*ht(自定义散列表指针)、*empty(bool类型指针,功能是将元素值空、m(散列表容量)、p(除留余数法的除数)...

    HashFiles(计算文件各种校验参数)1.10绿色版

    HashFiles是一款免费的实用程序,用来计算CRC32,MD5文件或多个文件的​​SHA256和SHA1哈希有用。你不会觉得很难使用的应用程序,它的用户界面是不言自明,需要的用户快来下载吧。 虽然有一个专门的按钮,你可以用...

    c#哈希算法的实现方法及思路

    有想过hash[“A1”] = ... 代码如下:static void Main(string[] args) { MyHash hash = new MyHash(); hash[“A1”] = DateTime.Now; hash[“A2”] = 1; Console.WriteLine(Convert.ToString(hash[“A1”])); 

    一个c++实现的哈希表类-C++文档类资源

    在程序中我们对关键字key应用散列函数H(key)来判断关键字key是否在散列表中,...程序的具体实现如下:本程序是用模板类myhash来实现,包括protected和public属性成员。其中protected成员有*ht(自定义散列表指针)、*e

    Hash、md5校验工具-哈希计算器

    Hash md5校验工具 是一款小巧好用的哈希计算器 Hash也是一款md5校验工具 Hash支持文件拖放 速度很快 可以计算文件的 MD5 SHA1 CRC32 的值 软件特色: 支持多个文件或文件夹拖放操作; 支持参数启动 参数为一个...

    java应用开发

    1.哈西表MyHash定义如下: Hashtable MyHash=new Hashtable(); 查看下列语句: MyHash.put(“ten”,new Integer(10)); MyHash.put(“ten”,”Hello”); System.out.print(MyHash.size()); 结果为( )。

    支持文件和文件夹的Hash计算工具

    多线程hash计算工具。安全可靠,电子数据提取固定必备。支持多线程MD5、SHA256、SHA512等多种hash计算,支持批量计算。

    一致性哈希

    * $servers[$this-&gt;myHash($key) % 2] 这样得到其中一台服务器的配置,利用这个配置完成分布式部署 * 在服务器数量不发生变化的情况下,普通hash分布可以很好的运作,当服务器的数量发生变化,问题就来了 * 试想...

    Digest-HMAC:HMAC for Perl

    $digest = hmac($data, $key, \&myhash); print hmac_hex($data, $key, \&myhash); # OO style use Digest::HMAC; $hmac = Digest::HMAC-&gt;new($key, "Digest::MyHash"); $hmac-&gt;add($data); $hmac-&gt;addfile&#40;*...

    wnmp(win+nginx+php+mysql)官方安装包

    - MyHash.exe - reMe.Md # 说明 所有文档均来自官网下载文件,内附MD5校验码(与官网一致)。某些包下载速度极慢(下载共用了5小时),为方便大家而上传的资料 #更新时间 2018-5-7(安装包均是 截止今日,官网发布的...

    js/jquery解析json和数组格式的方法详解

    语法: ECMAScript v3规定了数组直接量的语法,JavaScript 1.2和JScript 3.0实现了它。可以把—个用逗号分隔的表达式列表放在方括号中,创建并初始化—个数组。这些表达式的值将成为数组元素。例如: var a = [1, ...

    total commander

    2、精选实用工具:集成 Everything、MyHash、Notepad2、SwitchOFF 等工具,可实现文 件快速搜索、校验和计算、文本编辑、智能关机等功能; 3、拼音首字母定位:集成 QuickSearch eXtended 部分组件,实现中文...

    AngularJs返回前一页面时刷新一次前面页面的方法

    要求: 页面A进入到页面B,在页面B处理完后返回页面...以 ‘http://localhost/$location/21.1 $location.html#/foo?name=bunny#myhash’ 这个路径为例: 1. 获取当前完整的url路径: $location.absUrl(): // http://loca

    Go语言常见哈希函数的使用

    myhash.go /** * Created with IntelliJ IDEA. * User: liaojie * Date: 12-9-8 * Time: 下午3:53 * To change this template use File | Settings | File Templates. */ package main import ( crypto/md5 ...

Global site tag (gtag.js) - Google Analytics