您的位置:首页 > 编程语言 > Java开发

HashMap之Java实现

2014-03-20 23:00 225 查看
HashMap是使用最频繁、最重要的数据结构之一,提供了字典操作功能,Insert、Search、Delete操作的效率都很高。本文将尝试用Java实现一个最简单的HashMap。因为简单,才容易看到HashMap的本真设计思想。

什么是Hash

依我的理解,Hash就是把一个对象转化为一个正整数的过程。相同的对象产生相同的Hash Code,但不同的对象的Hash Code具有随机的特点,不同的Hash Code均匀分布。不同的对象也可能Hash Code相同,产生碰撞。

为什么Hash

Map存储的是键值对,存储的方式一般通过数组来完成。假设Key的可能集合为S,如果不Hash,那么要创建一个size大于等于S.length的数组来存储键,否则某些Key可能找不到槽位来放数据。当S很大,而真正使用到的数据又相对较小的时候,会造成空间的浪费。把S映射到一个较小的集合R,Hash正好用来做这样的Mapping,只不过得到的整数要处理一下,大小控制在R的范围之内。

具体实现

主要包括Insert(新增),Put(新增或者修改),Search(查询),Delete(删除)四个操作。Hash的过程利用了Object的hashcode(),也参考了算法导论的乘法Hash算法。解决碰撞使用了链表法,注意Node的next属性。

public class HashMap<K, V> {
	private static int DEFAULT_CAPACITY = 16;
	private static double A = (Math.pow(5, 0.5) - 1) / 2;

	private int capacity;
	private int size = 0;

	private Node<K, V>[] buckets;

	public HashMap() {
		this(DEFAULT_CAPACITY);
	}

	@SuppressWarnings("unchecked")
	public HashMap(int capacity) {
		if (capacity <= 0) {
			throw new IllegalArgumentException(
					"capacity can not be negative or zero");
		}

		// 保证 capacity 是2的n次方
		int temp = 1;
		while (temp < capacity) {
			temp <<= 2;
		}
		this.capacity = temp;

		buckets = new Node[this.capacity];
	}

	public void insert(K key, V value) {
		if (key == null) {
			throw new IllegalArgumentException("key can not be null");
		}

		int position = index(key);

		Node<K, V> node = new Node<K, V>(key, value);
		if (buckets[position] != null) {
			node.setNext(buckets[position]);
		}

		buckets[position] = node;
		size++;
	}

	public void put(K key, V value) {
		if (key == null) {
			throw new IllegalArgumentException("key can not be null");
		}

		int position = index(key);

		Node<K, V> node = buckets[position];

		while (node != null) {
			if (node.key.equals(key)) {
				node.value = value;
				return;
			}

			node = node.next;
		}

		Node<K, V> newNode = new Node<K, V>(key, value);
		if (buckets[position] != null) {
			newNode.setNext(buckets[position]);
		}

		buckets[position] = newNode;
		size++;
	}

	public void delete(K key) {
		if (key == null) {
			throw new IllegalArgumentException("key can not be null");
		}

		int position = index(key);
		Node<K, V> node = buckets[position];

		if (node == null) {
			return;
		}

		if (node.key.equals(key)) {
			buckets[position] = node.next;
			size--;
		}

		while (node.next != null) {
			if (node.next.key.equals(key)) {
				node.next = node.next.next;
				size--;
				break;
			}

			node = node.next;
		}
	}

	public V search(K key) {
		if (key == null) {
			throw new IllegalArgumentException("key can not be null");
		}

		int position = index(key);
		Node<K, V> node = buckets[position];

		while (node != null) {
			if (node.key.equals(key)) {
				return node.value;
			}

			node = node.next;
		}

		return null;
	}

	public int size() {
		return size;
	}

	public boolean isEmpty() {
		return size == 0;
	}

	@Override
	public String toString() {
		StringBuffer buffer = new StringBuffer();
		buffer.append("{");

		for (int i = 0; i < capacity; i++) {
			Node<K, V> node = buckets[i];
			while (node != null) {
				buffer.append(node.key + ":" + node.value + ", ");
				node = node.next;
			}
		}

		if (buffer.length() > 1) {
			buffer.delete(buffer.length() - 2, buffer.length());
		}

		buffer.append("}");

		return buffer.toString();
	}

	private int index(K key) {
		int hashCode = key.hashCode();

		double temp = hashCode * A;
		double digit = temp - Math.floor(temp);

		return (int) Math.floor(digit * capacity);
	}

	static class Node<K, V> {
		private final K key;
		private V value;
		private Node<K, V> next;

		public Node(K key, V value) {
			this.key = key;
			this.value = value;
		}

		public V getValue() {
			return value;
		}

		public void setValue(V value) {
			this.value = value;
		}

		public Node<K, V> getNext() {
			return next;
		}

		public void setNext(Node<K, V> next) {
			this.next = next;
		}

		public K getKey() {
			return key;
		}
	}

	public static void main(String[] args) {
		HashMap<String, String> map = new HashMap<String, String>();
		map.put("001", "James");
		map.put("002", "Antony");
		map.put("003", "Bosh");
		map.put("004", "Wade");
		map.put("004", "WestBrook");

		System.out.println(map);
		System.out.println(map.size());
		System.out.println(map.search("004"));
	}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: