`
zwhc
  • 浏览: 264738 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

Hashtable 源码阅读

阅读更多
今天复习一下 Hashtable 的基本原理。看了下源码,找了点资料。

下面这个文章,写得相当完整了。
http://tonylian.iteye.com/blog/384080
以下简称引文。

这篇文章是以 .net 为例的。

java 的有一点区别。

一、初始容量 和加载因子
Hashtable 的实例有两个参数影响其性能:初始容量和加载因子。容量 是哈希表中桶 的数量,初始容量 就是哈希表创建时的容量。注意,哈希表的状态为 open:在发生“哈希冲突”的情况下,单个桶会存储多个条目,这些条目必须按顺序搜索。加载因子 是对哈希表在其容量自动增加之前可以达到多满的一个尺度。初始容量和加载因子这两个参数只是对该实现的提示。关于何时以及是否调用 rehash 方法的具体细节则依赖于该实现。

通常,默认加载因子(.75)在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查找某个条目的时间(在大多数 Hashtable 操作中,包括 get 和 put 操作,都反映了这一点)。

默认初始化,初始容量为 11,加载因子为 0.75。
	public Hashtable() {
		this(11, 0.75f);
	}


引文中有如下描述:
数组容量 Array.Length 期望是一个 "比较大的质数", 这样 f(K) = HashOf(K) % Array.Length 取模运算之后得出的数冲突机会较小. 想象一个极端例子, 假设 Array.Length = 2, 则只要 HashOf(K) 是偶数, f(k) 都为 0. 所以说哈希表的实际容量一般都是有规律的, 和数组不一样, 不能任意设置.

二、hashtable 的存取

引文中描述到:
Hashtable 中的实际数据都存储在一个内部 Array 中 (当然和普通数组一样, 有固定容量, 上下标, 以数字索引存取), 当用户希望取得 Hashtable[K] 值的时候, Hashtable 进行如下处理:

[1] 为了保证 f(K) 的取值范围在  0 <= f(K) < Array.Length, 函数 f 的关键步骤是取模运算, 算得实际数据存储位置为 f(K) = HashOf(K) % Array.Length, 至于这个 HashOf(K) 怎么算出来的, 简单举例来说她可以取关键字的 ASCII 码根据一定规则运算得到.

[2] 如果发生多个 K 值的哈希值重复, 即 f(K1) = f(K2), 而 f(K1) 位置已经有数据占用了, Hashtable 采用的是 "开放定址法" 处理冲突, 具体行为是把 HashOf(K2) % Array.Length 改为 (HashOf(K2) + d(K2)) % Array.Length , 得出另外一个位置来存储关键字 K2 所对应的数据, d 是一个增量函数. 如果仍然冲突, 则再次进行增量, 依此循环直到找到一个 Array 中的空位为止. 将来查找 K2 的时候先搜索 HashOf(K2) 一档, 发现不是 K2, 那么增量 d(K2) 继续搜索, 直到找到为止. 连续冲突次数越多, 搜索次数也越多, 效率越低.


put 和 get 的源码

	public synchronized V get(Object key) {
		Entry tab[] = table;
		int hash = key.hashCode();
		int index = (hash & 0x7FFFFFFF) % tab.length;
		for (Entry<K, V> e = tab[index]; e != null; e = e.next) {
			if ((e.hash == hash) && e.key.equals(key)) {
				return e.value;
			}
		}
		return null;
	}
	public synchronized V put(K key, V value) {
		// Make sure the value is not null
		if (value == null) {
			throw new NullPointerException();
		}

		// Makes sure the key is not already in the hashtable.
		Entry tab[] = table;
		int hash = key.hashCode();
		int index = (hash & 0x7FFFFFFF) % tab.length;
		for (Entry<K, V> e = tab[index]; e != null; e = e.next) {
			if ((e.hash == hash) && e.key.equals(key)) {
				V old = e.value;
				e.value = value;
				return old;
			}
		}

		modCount++;
		if (count >= threshold) {
			// Rehash the table if the threshold is exceeded
			rehash();

			tab = table;
			index = (hash & 0x7FFFFFFF) % tab.length;
		}

		// Creates the new entry.
		Entry<K, V> e = tab[index];
		tab[index] = new Entry<K, V>(hash, key, value, e);
		count++;
		return null;
	}



其中,这一句比较关键。

int index = (hash & 0x7FFFFFFF) % tab.length;

tab.length 就是容量。

更详细的,可以自行阅读一下源码。
0
0
分享到:
评论
1 楼 zwhc 2010-08-06  
既然初始容量最好为质数,那么,贴一个质数的东东吧。

http://topic.csdn.net/t/20040821/22/3297408.html

代码主要来自于这里。做了一点修改:
1、直接指定开始值为终止值
2、输出到文件里。

package test;

import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class PrimeExplorer {
	public static void main(String[] args) throws IOException {
		int startValue;
		int endValue;
		int n;
		int sqrt;
		int divisor;
		int count;
		Prime head;
		Prime tail;
		Prime prime;
		boolean isPrime;
		BufferedReader in;

		in = new BufferedReader(new InputStreamReader(System.in));

		// Get input.
//		do {
//			try {
//				//System.out.print("From:   ");
//				startValue = Integer.parseInt(in.readLine());
//				//System.out.print("To:       ");
//				endValue = Integer.parseInt(in.readLine());
//				// Start from 11.
//				if (startValue < 11 || endValue <= startValue) {
//					continue;
//				} else {
//					break;
//				}
//			} catch (NumberFormatException e) {
//				continue;
//			}
//		} while (true);
		startValue = 11;
		endValue = 10000000;

		n = startValue;
		// Start from even.
		if (n % 2 == 0) {
			n++;
		}
		count = 0;

		// Prepare all prime numbers in 10 except 1.
		head = new Prime(5);
		head.next = new Prime(3);
		head.next.next = new Prime(7);
		prime = head;
		tail = head.next.next;

		// ========================================
		long startTime = System.currentTimeMillis();
		
		FileOutputStream fo = new FileOutputStream("prime.txt");
		fo.write(("2\r\n3\r\n5\r\n7\r\n").getBytes());

		for (isPrime = true; n < endValue; n += 2, prime = head, isPrime = true) {

			sqrt = (int) Math.sqrt(n) + 1;

			// Find prime number.
			for (divisor = prime.value; prime.next != null; prime = prime.next, divisor = prime.value) {
				if (n % divisor == 0) {
					isPrime = false;
					break;
				} else if (divisor > sqrt) {
					break;
				}
			}

			// Append this prime number to the list tail.
			if (isPrime) {
				count++;
				prime = tail;
				prime.next = new Prime(n);
				tail = prime.next;
				// TODO: Uncommont this for validating result.
				// System.out.println(n);
				fo.write((n+"\r\n").getBytes());
				//fo.write("/r/n".getBytes());
			}
		}

		System.out.println("Total:   " + count);
		long endTime = System.currentTimeMillis();
		System.out.println("cost:   " + (endTime - startTime));
		// ========================================
	}

	private static class Prime {
		public Prime next = null;
		public int value;

		public Prime(int value) {
			this.value = value;
		}
	}
}

相关推荐

    HashTable源码(JDK1.7,含注释)

    HashTable源码(JDK1.7,含注释)

    Session HashTable 购物车源代码

    在IT领域,尤其是在Web开发中,`Session`和`HashTable`是两个重要的概念,它们在构建功能丰富的应用程序,特别是像购物车这样...如果你在阅读和理解源代码过程中遇到任何问题,可以向提供QQ的作者提问,进行学习交流。

    Java集合专题总结:HashMap 和 HashTable 源码学习和面试总结

    Java集合专题总结:HashMap和HashTable源码学习和面试总结 本文总结了Java集合专题中的HashMap和HashTable,涵盖了它们的源码学习和面试总结。HashMap是一种基于哈希表的集合类,它的存储结构是一个数组,每个元素...

    Java 实例 - 使用 Enumeration 遍历 HashTable源代码+详细指导教程.zip

    本教程将深入探讨如何使用`Enumeration`接口遍历`HashTable`,并提供详细的源代码实例及指导。`Enumeration`在Java早期版本中用于迭代容器中的元素,虽然在Java集合框架的后续版本中被迭代器(Iterator)所取代,但...

    HashTable

    本文将深入探讨基于C语言实现的HashTable,解析其源码,揭示其工作原理和优化策略。 一、哈希表的基本概念 1. 哈希函数:哈希表的核心是哈希函数,它将键转化为数组索引,使得键值可以快速定位。一个好的哈希函数...

    HashMap与HashTable的区别(含源码分析)

    在Java编程语言中,`HashMap`和`HashTable`都是实现键值对存储的数据结构,但它们之间存在一些显著的区别,这些区别主要体现在...对于学习和理解,源码阅读是非常有价值的,可以帮助深入理解Java集合框架的设计原理。

    C语言hashtable

    通过阅读和理解这段代码,你可以深入学习哈希表的工作原理,并且了解到如何在C语言中实现这一重要的数据结构。同时,这也可以作为进一步优化哈希表性能的基础,比如调整哈希函数、优化冲突解决策略等。

    Hashtable代码

    .NET中Hashtable的源代码,Reflector出来的,并且消除了一些错误.可以直接使用.在03下编译通过

    Java 实例 - 遍历 HashTable 的键值源代码+详细教程.zip

    这个压缩包“Java 实例 - 遍历 HashTable 的键值源代码+详细教程.zip”包含了关于如何遍历`HashTable`的详细教程和源代码,对于学习Java的初学者或者需要深入了解`HashTable`操作的开发者来说,这是一个非常宝贵的...

    希哈表C源代码工程hashtable

    了解这些基本概念后,你可以通过阅读源代码来深入理解哈希表的实现细节,例如散列函数的设计、冲突解决策略的实现以及动态调整大小的过程。这对于学习数据结构和算法,特别是对C语言编程者来说,是非常有价值的实践...

    【STL源代码】C++标准库STL源代码下载

    阅读STL源代码可以帮助我们理解C++容器和算法的底层实现,从而优化自己的代码,提高程序性能。同时,也能让我们更好地掌握C++模板机制,以及如何利用泛型编程来编写高效且可复用的代码。通过分析源码,我们可以学习...

    C++ STL库源代码(SGI版本)

    通过阅读源代码,你可以了解各种算法如何与容器和迭代器协同工作,以及如何实现通用性和效率。 5. **stl_rope.h, ropeimpl.h**:Rope是一种特殊的数据结构,用于高效处理大字符串的拼接和切分操作。它通过将字符串...

    stl源码剖析源代码-免费

    通过阅读这些源代码,开发者可以深入理解STL内部的实现细节,比如迭代器的工作方式、容器的内存管理策略以及算法的效率优化。这对于提升C++编程技巧,特别是进行高性能、低级别的内存管理和优化时,是极其宝贵的资源...

    hash_src.zip_c hashtable_hash_hashtable

    标题"hash_src.zip_c hashtable_hash_hashtable"表明这是一个关于C语言实现哈希表的源代码,可能包含了哈希函数和冲突解决策略的实现。"hashtable"通常指的是哈希表的存储结构,而"hash"可能指的是哈希函数。 描述...

    Java容器之Hashtable源码分析

    【Java容器之Hashtable源码分析】 在Java编程中,`Hashtable`是一个古老的容器类,它继承自`Dictionary`接口,并实现了`Map`接口,同时也实现了`Cloneable`和`Serializable`接口。`Hashtable`与`HashMap`类似,都是...

    字典源代码--JAVA关于小字典的几个源代码

    以下是对"字典源代码--JAVA关于小字典的几个源代码"的详细解释: 1. **Map接口**: Map是Java集合框架的一部分,它定义了存储键值对的方法。主要方法包括`put(key, value)`用于添加元素,`get(key)`用于根据键获取值...

    dtl.zip_hashtable_hashtable delphi_结构

    通过查看源代码,开发者可以深入了解其内部实现,包括哈希函数的选择、冲突解决策略(如开放寻址法或链地址法)、内存管理以及对泛型的支持方式等。 在实际开发中,哈希表常用于数据库索引、缓存系统、映射关系的...

    hashtable hash表 散列表 C源代码

    哈希表(Hash Table),又称为散列表,是一种数据结构,它通过把关键码值映射到表中一个位置来实现查找,使得插入和查找数据的速度都非常快。在C++编程语言中,虽然标准库没有直接提供哈希表的数据结构,但我们可以...

Global site tag (gtag.js) - Google Analytics