散列函数,主要目的是需找一个好的散列方法把这个数组的每一个位置都能均匀的用到,下面先上一个比较好的散列函数实现
散列函数
1 package com.wuxing; 2 3 /** 4 * 散列函数 5 * @author wuxing 6 * 7 */ 8 public class Hash { 9 10 /** 11 * 12 * @param key 键值 13 * @param tableSize 存放数组的长度 14 * @return 存放键值在数组的位置 15 */ 16 public static int hash(String key,int tableSize){ 17 int hashVal=0; 18 for(int i=0;i<key.length();i++){ 19 hashVal=37*hashVal+key.charAt(i); 20 } 21 hashVal%=tableSize; 22 if(hashVal<0) 23 hashVal+=tableSize; 24 return hashVal; 25 } 26 27 28 29 30 }
然后对于散列表的实现,主要又分离散列表和开放地址法,分离散列表就是在一个数组中,如果对于有地址冲突的数据,则放在一个横向的链表中进行保存,具体实现如下
分离散列表的实现
1 package com.wuxing; 2 3 import java.util.LinkedList; 4 5 /** 6 * 分离散列表的实现,如果有重复的数字,即有hash冲突,则放在横向的链表中保存 7 * @author wuxing 8 * 9 */ 10 public class SeparateChainingHashTable { 11 private static final int DEFAULT_TABLE_SIZE=101; 12 13 //散列表的数组 14 private LinkedList<Object>[] theLists; 15 16 public SeparateChainingHashTable(){ 17 this(DEFAULT_TABLE_SIZE); 18 } 19 20 public SeparateChainingHashTable(int size){ 21 theLists=new LinkedList[size]; 22 for(int i=0;i<theLists.length;i++){ 23 theLists[i]=new LinkedList<Object>(); 24 } 25 } 26 27 28 public void makeEmpty(){ 29 for(int i=0;i<theLists.length;i++){ 30 theLists[i].clear(); 31 } 32 } 33 34 public void remove(Hashable x){ 35 theLists[x.hash(theLists.length)].remove(); 36 } 37 38 public Hashable find(Hashable x){ 39 return (Hashable)theLists[x.hash(theLists.length)] 40 .get(0);} 41 } 42 43 44 interface Hashable{ 45 int hash(int tableSize); 46 }
对于开散列法,如果又地址冲突的数据,则进行查找下一个地址是否没有使用,如果没有使用则插入,比较流行的是平方探测法比较好
开放地址法散列表
1 package com.wuxing; 2 3 import java.security.AllPermission; 4 5 class HashEntry { 6 Hashable element; //元素 7 boolean isActive;//懒惰删除的实现标记 8 9 public HashEntry(Hashable e,boolean i){ 10 element=e; 11 isActive=i; 12 } 13 } 14 15 class QuadraticProbingHashTable{ 16 private static final int DEFAULT_TABLE_SIZE=11; 17 private HashEntry[] array; 18 19 private int currentSize; 20 21 public QuadraticProbingHashTable(){ 22 this(DEFAULT_TABLE_SIZE); 23 } 24 25 public QuadraticProbingHashTable(int defaultTableSize) { 26 allocateArray(defaultTableSize); 27 makeEmpty(); 28 } 29 30 private void allocateArray(int defaultTableSize) { 31 array=new HashEntry[defaultTableSize]; 32 } 33 34 private void makeEmpty() { 35 currentSize=0; 36 for(int i=0;i<array.length;i++){ 37 array[i]=null; 38 } 39 } 40 41 /** 42 * 解决查找冲突问题 43 * @param x 44 * @return 45 */ 46 private int findPos(Hashable x){ 47 int collisionNum=0; 48 int currentPos=x.hash(array.length); 49 50 while(array[currentPos]!=null&&!array[currentPos].element.equals(x)){ 51 currentPos+=2*++collisionNum-1; 52 if(currentPos>array.length) 53 currentPos-=array.length; 54 } 55 return currentPos; 56 } 57 58 public Hashable find(Hashable x){ 59 int currentPos=findPos(x); 60 return isActive(currentPos)?array[currentPos].element:null; 61 } 62 63 private boolean isActive(int currentPos) { 64 return array[currentPos]!=null&&array[currentPos].isActive; 65 } 66 67 }