java实现简单的散列数据结构

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq1004642027/article/details/45367765

散列表的实现是一种在时间和空间上做出权衡的方式。对于数组存储,如果们没有内存限制,则可以直接将数据作为键作为数组的索引,那么所有的查询操作都只需要一次访问内存即可完成。但是当键很多的时候,需要的内存会非常大,所以这种方式不可能实现。

另一方面,如果没有时间限制,我们可以对数组进行遍历查找,来查询数组里面的数据。这样会耗费比较多的时间。

散列表是一种折中的方法,在这两个极端之间找到一个权衡。


散列表的两个步骤:

第一:利用对象的hashCode()函数,求出对象的hash值,利用hash函数(hash函数有很多,这里使用除留余数法),将对象的hash值映射到内存中去(即求出在数组中 的索引)。

第二:在映射的过程中,当两个不同的对象可能会映射到同一个内存单元中时,就发生了碰撞冲突,第二部就是要解决碰撞冲突问题。这里是利用链表,每个数组单元 中,存放一个链表。将映射到同一内存单元的多个元素,存放到链表中。



package hashtable;

import java.util.LinkedList;
import java.util.List;

/*
 * hashtable的数据结构
 * 使用
 * 		hash函数:除留余数法
 * 		碰撞解决:分离链接法
 */
public class Table<anyType> {
	private static final int DEFUALT_TABLE_SIZE=101;
	private List<anyType>[] theList;
	private int currentSize;
	
	public Table(){
		this(DEFUALT_TABLE_SIZE);
	}
	
	public Table(int tableSize){
		theList = new LinkedList[tableSize];
		for(int i=0;i<tableSize;i++)
			theList[i] = new LinkedList<anyType>();
	}
	
	public void insert(anyType xType){
		List<anyType>whichList = theList[myHash(xType)];
		System.out.println("数组的索引:"+myHash(xType)+"\t对象的哈希值:"+xType.hashCode());
		if(!whichList.contains(xType)){
			whichList.add(xType);		//whichList只是一个指向theList数组中指定位置的指针,故操作的实际上还是theList数组对象
			currentSize++;
		}
	}
	
	public void remove(anyType xType){
		List<anyType>whichList=theList[myHash(xType)];
		if(whichList.contains(xType)){
			whichList.remove(xType);
			currentSize--;
		}
	}
	
	public boolean contain(anyType xType){
		List<anyType>whichList=theList[myHash(xType)];
		return whichList.contains(xType);
	}
	
	public void makeEmpty(){
		currentSize=0;
		for(int i=0;i<theList.length;i++)
			theList[i].clear();
	}
	
	private int myHash(anyType xType){
		int hashVal=0;
		hashVal=xType.hashCode()%theList.length;
		if(hashVal<0)
			hashVal+=theList.length;
		return hashVal;
	}

	public static void main(String[] args) {
		Table<people> hashTable = new Table<people>(11);
		for(int i=0;i<11;i++)
			hashTable.insert(new people("xiaoming"+i, 20+i));
		hashTable.remove(new people("xiaoming0", 20));
		System.out.println("该对象已经被删除,散列中是否还包含该对象:"+hashTable.contain(new people("xiaoming0", 20)));
	}
}

/*
 * 自定义对象,为了能够进行散列,需要实现hashCode和equal方法
 */
class people{
	private String name;
	private int age;
	public people(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		people other = (people) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	
}

测试中添加11个对象,将这11个对象散列到初始大小为11的散列表中,运行结果可以看到,大部分情况下,元素是均匀分布在数组中的。

删除掉对象new people("xiaoming0", 20)之后,散列表中就不再包含该对象。对象相等这里是根据重载的equal方法来判断的,而不是对象的地址相等。


运行结果:

数组的索引:5	对象的哈希值:-364430039
数组的索引:4	对象的哈希值:-364430007
数组的索引:3	对象的哈希值:-364429975
数组的索引:2	对象的哈希值:-364429943
数组的索引:1	对象的哈希值:-364429911
数组的索引:0	对象的哈希值:-364429879
数组的索引:10	对象的哈希值:-364429847
数组的索引:9	对象的哈希值:-364429815
数组的索引:8	对象的哈希值:-364429783
数组的索引:7	对象的哈希值:-364429751
数组的索引:8	对象的哈希值:1587523638
该对象已经被删除,散列中是否还包含该对象:false

散列表的构造主要就是这两步:

第一:根据hashCode与合适的散列函数算法,将存储对象均匀散列到存储数组中去。哈希算法还有很多种,直接定址法,除留余数法等等

第二:解决碰撞冲突问题。解决方法有,分离链接法,开放定址法等等

展开阅读全文

没有更多推荐了,返回首页