`
黑色骑士
  • 浏览: 4018 次
  • 性别: Icon_minigender_1
  • 来自: 绍兴
最近访客 更多访客>>
社区版块
存档分类
最新评论

用java实现hashmap

阅读更多
虽然很想很早就想写一个hash表,但一直都未去实现。通过这次机会,算是对hash表有了一个比较直观的了解,主要有以下几点(都是个人见解):
1.哈希表的目的在于加快查找速度,用一个形象的比喻就是hash是将一个排好序的数据存入 数组中,所以在查找时能通过这个索引迅速找到所需要的元素,在hash表中,数组才是主体,链表只是辅助,甚至可以不存在。
2.产生这个索引(在hash中是key)的函数和方法各种各样,而判别这个方法优劣就是让其尽可能少得产生冲突,因为产生冲突后,就会调用处理冲突的方法,无论哪一种方法都不是很合适,以链表为例,显然链表是不适合查找的,所以这个方法对表性能的影响是很大的。这里我才用了和系统差不多的方法,采用了&运算,其实类似于mod,但速度更快。
3.处理冲突的方法也有不少。其中我比较明白的是再散列法和拉链法。在散列法的思想很简单,就是产生冲突后重新计算hash函数地址(索引值)直到找到空的空间放数据。而拉链法则是运用的链表的逻辑连续特性,使不同的数据存在同一个哈希地址下。我采用了第二种,所以对其优缺点比较了解,缺点很明显就是增加查找的复杂度,而相对与再散列法的优点还是很大的,可以避免重复的计算hash地址。
4.如何resize,当装载数与数组长度的比例大于等于比例因子,这是说明数组容量快要饱和,为了避免产生大量的冲突,必须采用resize。
   而在写代码的过程中也考虑了很久。比如在数组中存什么,数组长度定义多少之类。这里我说说我的方法。数组中我存的是链表的首节点,因为链表的特性,只要知道头就可以获得整个链表,于此匹配的,我也采用了头插法,当产生冲突,我把它放在链表的头位置。这样代码可以减少不少。至于数组长度我定义为2^n,原因与&运算有关,因为2^n-1的二进制所有位都为1,这样的与运算可以使冲突尽量减少。当产生冲突时,数组长度扩大一倍,感觉也是比较合理的。
以下是部分代码
/**
 * 结点类
 * @author zrq
 *所有数据类都必须继承这个结点类
 */
public class Node {
    private  String account;//账号是唯一标示
    private  String password;
    private  Node Next;

    public int hashcode()
    {
    	int hash=1;
    	hash=Integer.parseInt(account);
    	return hash;
    }

	public String getAccount() {
		return account;
	}

	public void setAccount(String account) {
		this.account = account;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public Node getNext() {
		return Next;
	}

	public void setNext(Node next) {
		Next = next;
	}

}

由于我是采用了数字作为测试数据,所以节点中的属性是直接定义的(account是唯一的)。重写了hashcode(),产生的方法就是采用了account这个唯一的属性(不通用)。
public class MyHashMap {
	private int initial_size = 16;// 数组初始大小
	private int finally_size = 16;// 用来记录现在数组大小
	private double balance = 0.75;// 装载因子
	private Node[] mapNodes;//组成数组
	private int count = 0;// 用于计数
	int hash;
	int index;

	// 初始化时开辟数组空间
	public MyHashMap() {
		mapNodes = new Node[initial_size];
	}

	public void put(Node node) {
		hash = node.hashCode();// 可修改
		index = hash & (finally_size - 1);// 获得索引位置
		Node fi = mapNodes[index];
		if (fi == null) {
			mapNodes[index] = node;
			count++;
			if (count > finally_size * balance)
				reSize();

		} else {
			// System.out.println("test " + mapNodes[index].head.getAccount());
			node.setNext(fi);
			mapNodes[index] = node;
		}
	}
    /**
     * 通过account查找的方法
     * @param x:account
     * @return:  password
     */
	public String GetValue(String x) {
		Node s = new Node();
		s.setAccount(x);
		boolean f = false;
		int hash = s.hashcode();
		index = hash & (finally_size - 1);
		Node n = mapNodes[index];
		while (n != null) {
			if (n.getAccount().equals(x)) {
				f = true;
				break;
			}
			n = n.getNext();
		}
		if (f)
			return n.getPassword();
		else {
			System.out.println(finally_size);
			return "null";
		}
	}

/**
 * 当达到装载因子时扩容
 */
	public void reSize() {
		count=0;
		Node[] copy = new Node[finally_size * 2];
		for (int i = 0; i < finally_size; i++) {
			Node node = mapNodes[i];
			Node dnext;
			while (node != null) {
				//System.out.println("de"+node.getAccount());
				dnext = node.getNext();
				int index = node.hashcode() & (finally_size * 2 - 1);
				if (copy[index] == null) {
					node.setNext(null);
					copy[index] = node;
					count++;
				} else {
					Node t = copy[index];
					node.setNext(t);
					copy[index] = node;

				}
				node = dnext;
			}

		}
		finally_size = finally_size * 2;
		mapNodes = copy;
	}
}

写的比较急,没怎么优化。
以下是测试类。我用1000000个连续的号码进行存储和查找的测试。系统的时间大概在2600ms,我的大概在3000ms。查找100000个数据,我的约为90ms,系统在120ms左右,当然这和我的node设置的针对性也有关系。
以下是myhashmap的测试主函数(将da放的位置改变就可以测试不同的时间)
	 public static void main(String[] args) {
	 // TODO Auto-generated method stub
	 File fi = new File("F:\\test.txt");
	
	 try {
	 MyHashMap map = new MyHashMap();
	 // HashMap< String, String> map=new HashMap<String, String>();
	 Scanner scan = new Scanner(fi);
	
	 while (scan.hasNext()) {
	 String s = scan.next();
	 Node node = new Node();
	 node.setAccount(s);
	 node.setPassword(s);
	 map.put(node);
	 }

	 int x=100000;
	 Date da = new Date();
	 long n = da.getTime();
	 while(x-->0)
	 {
	 map.GetValue(""+x);
	 }
	 Date de = new Date();
	 long t = de.getTime();
	 System.out.println(t - n + "ms");
	 } catch (FileNotFoundException e) {
	 // TODO Auto-generated catch block
	 e.printStackTrace();
	 }
	
	 }

以下是系统的测试主函数
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		File fi = new File("F:\\test.txt");

		try {
			HashMap<String, String> map = new  HashMap<String, String>();
			Scanner scan = new Scanner(fi);
			int x = 100000;
			while (scan.hasNext()) {
				String s = scan.next();
				map.put(s, s);
			}
			Date da = new Date();
			long n = da.getTime();
			while (x-- > 0) {
				map.get("" + x);
			}
			Date de = new Date();
			long t = de.getTime();
			System.out.println(t - n + "ms");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

hash的内容还有很多,先写到这。至于哈希算法,很多在安全领域涉及,比如MD5(深奥啊),以后再补充吧。
分享到:
评论

相关推荐

    Java中用hashmap实现购物车

    Java语言使用hashmap实现向购物车添加删除修改商品,显示商品信息

    自定义map实现java的hashmap

    在Java编程中,HashMap是一个非常重要的数据结构,它实现了Map接口,提供了键值对的存储功能,具有快速存取和高效查找的特点。HashMap基于哈希表(也称为散列表)原理,通过键对象的哈希码来定位元素,进而实现O(1)...

    Java中HashMap的工作机制

    在Java中,HashMap是一种广泛使用的数据结构,它基于哈希表的Map接口实现。哈希表是一种通过哈希过程将键映射到特定位置的数据结构,该位置存储了键对应的值。在详细探讨Java中HashMap的工作机制之前,首先需要理解...

    java中HashMap详解.pdf

    Java中的HashMap是一种基于散列机制的Map接口的实现,它允许我们存储键值对。键是唯一的,而值可以重复。HashMap在处理数据时非常高效,因为其操作的时间复杂度接近于O(1)。这是通过使用散列函数将键映射到相应的...

    js 版 java hashmap

    JavaScript中的HashMap并不是内置的数据结构,但在许多开发场景中,我们需要实现类似Java中HashMap的功能,用于存储键值对数据。在JavaScript中,我们通常使用对象(Object)来模拟HashMap的行为,因为对象的属性名...

    Java HashMap类详解

    本资源详细介绍了 Java 中的 HashMap 类,包括其实现机制、Hash 存储机制、集合存储机制等方面的知识点。 1. HashMap 和 HashSet 的关系 HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,虽然...

    java中HashMap,LinkedHashMap,TreeMap,HashTable的区别

    `HashMap`是一种基于哈希表实现的`Map`接口,提供了一个非同步的、允许使用`null`键和值的存储结构。`HashMap`通过计算对象的哈希码来存储和检索对象,这使得数据可以在常数时间内被访问。 - **特点**: - **非...

    js 实现HashMap功能

    用js代码实现java中hashmap 的所有功能

    java HashMap原理分析

    5. Java中HashMap的应用和实现 详细解释: 1. 哈希函数的原理和应用 哈希函数是一种将输入数据转换为固定长度的哈希码的函数。在HashMap中,哈希函数用于将Key转换为一个哈希码,然后根据哈希码将Key-Value对存储...

    基于HashMap的用户标签处理兼Java中HashMap实现原理研究.pdf

    "基于HashMap的用户标签处理兼Java中HashMap实现原理研究" 本文研究了基于HashMap的用户标签处理方法,并对Java中HashMap的实现原理进行了深入研究。HashMap是一种高效的数据结构,可以快速地存储和检索数据。本文...

    Java-HashMap.rar_hashmap_java hashmap

    总的来说,理解并熟练使用`HashMap`对于Java开发者来说至关重要,因为它在数据存储和检索方面提供了高效且灵活的解决方案。在学习和使用`HashMap`时,不仅要掌握其基本用法,还要了解其内部工作原理,包括哈希函数、...

    Java8HashMap键与Comparable接口编程开

    总结来说,Java 8 HashMap键与Comparable接口的结合使用,使得我们能够在保持HashMap高效性能的同时,方便地对键进行排序,特别是在使用Java 8的新特性如Stream API时。通过实现Comparable接口,我们能够自定义对象...

    Java中HashMap详解(通俗易懂).doc

    Java中的HashMap是一个非常重要的数据结构,它实现了Map接口,提供了键值对的高效存储和访问。HashMap基于哈希表(也称为散列表)原理工作,它允许用户通过键(Key)快速查找对应的值(Value)。在HashMap中,键和值...

    Java使用HashMap实现并查集

    Java使用HashMap实现并查集 Java使用HashMap实现并查集是指使用Java语言中的HashMap数据结构来实现并查集。并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以...

    java实现运用hashmap充当购物车goodbean充当存放数据.pdf

    在本资源中,我们将学习如何使用 Java 语言实现一个简单的购物车系统,其中使用 HashMap 来存放用户想买的商品信息。下面是该资源中的知识点总结: ConnDB.java ConnDB.java 是一个用于连接数据库的类,该类中...

    浅谈Java中HashMap类的使用.pdf

    Java 中 HashMap 类的使用详解 HashMap 是 Java 语言中最常用的集合类之一,它实现了 Map 接口,提供了 put、get、keySet 等常用方法来存储和检索数据。本文将详细介绍 HashMap 类的使用,包括其常用方法、特点和...

    java 使用web service读取HashMap里的数值

    通过以上步骤,我们成功地实现了使用Java WebService读取`HashMap`中的数值的功能。这种做法不仅适用于简单的数据交换场景,还能够扩展到更复杂的业务逻辑处理中。对于开发者而言,理解和掌握这一技术是构建稳定可靠...

    java中HashMap详解

    HashMap是Java编程语言中一种非常重要的数据结构,它实现了Map接口,主要用于存储键值对。HashMap内部基于哈希表(Hash Table)实现,利用哈希函数将键映射到一个特定的位置,以便快速查找和插入元素。以下是HashMap...

    深入Java集合学习系列:HashMap的实现原理

    在Java编程语言中,集合框架是开发者日常工作中不可或缺的一部分,HashMap作为其中的重要成员,它的实现原理对于理解Java性能优化和数据结构有深远的意义。HashMap是一个基于哈希表的数据结构,它实现了Map接口,...

    Java8 HashMap的实现原理分析

    Java8之后新增挺多新东西,接下来通过本文给大家介绍Java8 HashMap的实现原理分析,对java8 hashmap实现原理相关知识感兴趣的朋友一起学习吧

Global site tag (gtag.js) - Google Analytics