基于java的数据结构学习手记16-线性探测哈希表实现

来源:互联网 发布:windows应用程序开发 编辑:程序博客网 时间:2024/06/05 15:39

    哈希表是一种可以提供快速插入和查找操作的数据结构,查找和删除只需要接近常量的时间!操作速度快,编程实现也相对容易。哈希表的限制为程序员必须清楚表中要存储多少数据,比较难于扩展。另个缺点是没有很好的方法遍历哈希表。在不需要有序遍历,以及可以提前预测数据量大小的情况下,使用哈希表在速度和易用性方面是无与伦比的。

什么是哈希表?

我们日常使用的英文字典是个比较形象的哈希表的例子。假定现在把英语中从单词a到zyzzyva的50000个单词,都用编码来实现,来存入计算机内。一种编码方式是:用1来给a编码,2是b,...26是z,0表示空格。为了使得每个单词都有唯一的编码,决定只用幂的连乘,cat这个单词就可以用3*27*27+1*27+20(基值和权值的连乘之和)来表示。但是当单词比较长的时候比如zzzzzzzzz,编码所使用的整数范围会变得非常大。而在其中只有50000个编码代表的有效单词,大多数单元是空的。

哈希化

       这个时候就需要一种压缩方法,把连乘系统中的得到的大的整数范围压缩到可接受的数组范围中。对于50000个有效单词,最终编码容量压缩到100000(2倍于有效单词,保持一定的空闲率)比较合适。现在就是要找一直方法把0到超过7000000000000的范围,压缩到0到100000。有一种简单方法就是取余数。即把当前的编码对100000取余,结果作为新的该单词的编码。这样也会带来一个问题:有可能两个单词对100000取余后的结果是相同的,这样就会造成两个单词的重码。

  解决冲突的方案:由于指定的数组大小两倍于需要存储的数据量,因此,可能一半是空的。当冲突发生时,一个方法是通过系统的方法找到数组的一个空位,并把这个单词填入。这个方法叫做开放地址法。例如:cats哈希化的结果是5421,但它的位置已经被parsnip占用,那么可以考虑把cats放到5422的位置上。如果5422也被占用了,就用5423,依次类推。数组下标一直递增,直到找到空位。这叫做线性探测。

具体代码如下:

Code:
  1. import java.io.*;  
  2.   
  3. public class DataItem {  
  4.     private int iData;  //Data   
  5.   //------------------------------------------      
  6.     public DataItem(int ii)//构造函数  
  7.     {  
  8.         iData=ii;  
  9.     }  
  10.   //------------------------------------------     
  11.     public int getKey()  
  12.     {  
  13.         return iData;  
  14.     }  
  15. //------------------------------------------      
  16. }//end class DataItem  
Code:
  1. public class HashTable {  
  2.     private DataItem[]hashArray; //哈希表  
  3.     private int arraySize;      //数组大小  
  4.     private DataItem nonItem;  //针对删除的项  
  5. //-----------------------------------  
  6.     public HashTable(int size)//constructor  
  7.     {  
  8.        arraySize=size;       //Initialization  
  9.        hashArray=new DataItem[arraySize];  
  10.        nonItem=new DataItem(-1);  
  11.     }  
  12. //------------------------------------------  
  13.    public void displayTable()  
  14.    {  
  15.        System.out.print("Table: ");  
  16.        for(int j=0;j<arraySize;j++)  
  17.        {  
  18.            if(hashArray[j]!=null)  
  19.                System.out.print(hashArray[j].getKey()+" ");  
  20.            else  
  21.                System.out.print("** ");  
  22.        }  
  23.        System.out.println("");  
  24.    }  
  25. //------------------------------------------   
  26.    public int hashFunc(int key)  
  27.    {  
  28.        return key%arraySize;//hash function  
  29.    }  
  30. //------------------------------------------  
  31.    public void insert(DataItem item)//insert a DataItem  
  32.    {  //假定数组不满  
  33.        int key=item.getKey();  
  34.        int hashVal=hashFunc(key);  
  35.        while(hashArray[hashVal]!=null&&hashArray[hashVal].getKey()!=-1)  
  36.        {  
  37.            ++hashVal;  
  38.            hashVal%=arraySize;  
  39.        }  
  40.        hashArray[hashVal]=item;  
  41.    }//end insert()  
  42.  //------------------------------------------  
  43.  public DataItem delete(int key)//删除  
  44.  {  
  45.      int hashVal=hashFunc(key);  
  46.      while(hashArray[hashVal]!=null)  
  47.      {  
  48.          if(hashArray[hashVal].getKey()==key)  
  49.          {     
  50.              DataItem temp=hashArray[hashVal];  
  51.              hashArray[hashVal]=nonItem;  
  52.              return temp;  
  53.          }  
  54.          else  
  55.              ++hashVal;  
  56.          hashVal%=arraySize;  
  57.       }  
  58.      return null;  
  59. }//end delete  
  60. //------------------------------------------  
  61.  public DataItem find(int key)//寻找  
  62.  {  
  63.      int hashVal=hashFunc(key);//找到区间起点  
  64.      while(hashArray[hashVal]!=null)//遇到null终止  
  65.      {  
  66.          if(hashArray[hashVal].getKey()==key)//找到  
  67.              return hashArray[hashVal];  
  68.          else                                //否则向下查找  
  69.              ++hashVal;                        
  70.          hashVal%=arraySize;                //循环掉头wrap around  
  71.      }  
  72.      return null;                          //没找到返回null  
  73.  }  
  74.    
  75. }  
Code:
  1. import java.io.*;  
  2.   
  3. public class HashTableApp {  
  4.   
  5.     /** 
  6.      * @param args 
  7.      * @throws IOException  
  8.      */  
  9.     public static void main(String[] args) throws IOException {  
  10.         // TODO Auto-generated method stub  
  11.           DataItem aDataItem;  
  12.           int aKey,size,n,keysPerCell;  
  13.           System.out.print("输入哈希表的大小:");  
  14.           size=getInt();  
  15.           System.out.print("输入初始项的数量:");  
  16.           n=getInt();  
  17.           keysPerCell=10;  
  18.           HashTable theHashTable=new HashTable(size);  
  19.           for(int j=0;j<n;j++)  
  20.           {  
  21.              aKey=(int)(java.lang.Math.random()*keysPerCell*size);  
  22.              aDataItem=new DataItem(aKey);  
  23.              theHashTable.insert(aDataItem);  
  24.           }  
  25.           while(true)  
  26.           {  
  27.               System.out.print("输入以下指令的首字母");  
  28.               System.out.print("show,insert,delete or find: ");  
  29.               char choice=getChar();  
  30.               switch(choice)  
  31.               {  
  32.               case's':  
  33.                   theHashTable.displayTable();  
  34.                   break;  
  35.               case'i':  
  36.                   System.out.print("输入要插入的整数:");  
  37.                   aKey=getInt();  
  38.                   aDataItem=new DataItem(aKey);  
  39.                   theHashTable.insert(aDataItem);  
  40.                   break;  
  41.               case'd':  
  42.                   System.out.print("输入要删除的整数:");  
  43.                   aKey=getInt();  
  44.                   theHashTable.delete(aKey);  
  45.                   break;  
  46.               case'f':  
  47.                   System.out.print("输入要查询的整数:");  
  48.                   aKey=getInt();  
  49.                   aDataItem=theHashTable.find(aKey);  
  50.                   if(aDataItem!=null)  
  51.                   {  
  52.                       System.out.println("找到 "+aKey);  
  53.                   }  
  54.                   else  
  55.                       System.out.println("未找到"+aKey);  
  56.                   break;  
  57.               default:  
  58.                   System.out.print("非法输入/n");  
  59.               }//end switch  
  60.           }//end while  
  61.     } //end main()  
  62. //----------------------------------------------------------  
  63.     public static String getString()throws IOException  
  64.     {  
  65.         InputStreamReader isr=new InputStreamReader(System.in);  
  66.         BufferedReader br=new BufferedReader(isr);  
  67.         String s=br.readLine();  
  68.         return s;  
  69.     }  
  70. //----------------------------------------------------------  
  71.     public static char getChar()throws IOException  
  72.     {  
  73.         String s=getString();  
  74.         return s.charAt(0);  
  75.     }  
  76. //----------------------------------------------------------  
  77.     public static int getInt()throws IOException  
  78.     {  
  79.         String s=getString();  
  80.         return Integer.parseInt(s);  
  81.     }  
  82. //----------------------------------------------------------      
  83. }//end class HashTableApp  

输入结果为:

Code:
  1. 输入哈希表的大小:12  
  2. 输入初始项的数量:8  
  3. 输入以下指令的首字母show,insert,delete or find: s  
  4. Table: 0 ** 74 99 100 89 62 5 ** ** 46 **   
  5. 输入以下指令的首字母show,insert,delete or find: f  
  6. 输入要查询的整数:99  
  7. 找到 99  
  8. 输入以下指令的首字母show,insert,delete or find: i  
  9. 输入要插入的整数:66  
  10. 输入以下指令的首字母show,insert,delete or find: s  
  11. Table: 0 ** 74 99 100 89 62 5 66 ** 46 **   
  12. 输入以下指令的首字母show,insert,delete or find: d  
  13. 输入要删除的整数:100  
  14. 输入以下指令的首字母show,insert,delete or find: s  
  15. Table: 0 ** 74 99 -1 89 62 5 66 ** 46 **   
  16. 输入以下指令的首字母show,insert,delete or find:   

 

原创粉丝点击