zoukankan      html  css  js  c++  java
  • 哈希表的简单实现

    HashTable算法概要:
    哈希表示表示集合和字典的另外一种有效的方法,通过将关键码映射到表中
    某个位置来存储元素,然后根据关键码用同样的方式直接访问。
    1、有限的连续地址,可以用数组来表示。
    2、Hash函数采用除留余数法。
    3、处理冲突的方法,用开放地址法,实现线性探测再散列法,
    二次探测再散列法,随即探测再散列法,后两种方法有一些对条件的限制。
    4、给定一系列的键值,分配一个数组,用哈希函数处理地址,在哈希函数中调用
    冲突处理函数。
    5、查找函数。

    哈希表的类定义代码如下:

    class HashT{
    public:
    	
    	HashT(){}			//构造函数
    	~HashT(){}			//析构函数
    
    	//哈希函数
    	void  HashLFun(int key[],int keysize,int dest[],int destsize,int mod);	//哈希函数,算法采用除留余数法
    	void  HashQFun(int key[],int keysize,int dest[],int destsize,int mod);	//哈希函数,算法采用除留余数法
    	
    	//处理冲突函数
    	int  HashLinearPro(int H0,int i,int mod);	    //线性探测再散列法
    	int  HashQuadraticPro(int me,int H0,int mod,int flag);	//二次探测再散列法
    	
    	
    };
    

     哈希函数根据处理冲突的方法不同,分为两个。

    哈希函数(除留余数法)算法:采用线性探查再散列法
    1、传入键值数组、模值和目标数组。
    2、要处理一批键值,所以应该使用一个循环。
    3、采用除留余数法求第一次的地址值。
    4、判断是否产生了冲突,如果产生冲突,就调用冲突处理函数,寻找下一个可用的地址。

    算法代码如下:

    void HashT::HashLFun(int key[],int keysize,int dest[],int destsize,int mod)
    {
    	int destnum;
    	for(int i=0;i<keysize;i++)	//处理这个键值序列
    	{
    		destnum=key[i]%mod;		
    		int fuben=destnum;	//记录当前值,用于循环
    		if(dest[destnum]==0)
    		{
    			//如果该数组值等于0,说明没有发生冲突,则将该键值插入到该数组
    			dest[destnum]=key[i];
    		}
    		else
    		{
    			int count=i;		//保存i的值,不改变原程序中i的值
    			//否则发生了冲突,调用冲突处理函数,将key值赋值给下一个合适的位置
    			while(dest[destnum]!=0)	//如果冲突,继续循环处理
    			{
    				destnum=HashLinearPro(destnum,count,mod);
    				if(destnum!=fuben)	//如果i值小于总的大小,就继续增加探测
    					count++;
    				else
    					cout<<"表中不存在可以存储该键值的位置"<<endl;
    
    			}
    			//while循环之后,说明找到了这个位置
    			dest[destnum]=key[i];
    
    		}
    		
    	}
    
    }
    

     采用二次探查法解决冲突的算法代码如下:

    void HashT::HashQFun(int key[],int keysize,int dest[],int destsize,int mod)
    {
    	int destnum;
    	for(int i=0;i<keysize;i++)	//处理这个键值序列
    	{
    		destnum=key[i]%mod;		
    		int fuben=destnum;
    		if(dest[destnum]==0)
    		{
    			//如果该数组值等于0,说明没有发生冲突,则将该键值插入到该数组
    			dest[destnum]=key[i];
    		}
    		else
    		{
    			
    			int count=1;		
    			int flag=0;			//设定一个调用次数的标记
    			//否则发生了冲突,调用冲突处理函数,将key值赋值给下一个合适的位置
    			while(dest[destnum]!=0)	//如果冲突,继续循环处理
    			{
    				flag++;		//调用次数加1
    				destnum=HashQuadraticPro(count,destnum,mod,flag);
    				//if(count<destsize)	//如果i值小于总的大小,就继续增加探测
    					//count++;		//这个地方不严谨,应该可以回到最初的位置
    				//else
    					//cout<<"表中不存在可以存储该键值的位置"<<endl;
    			
    				if(flag%2==0){
    				//如果循环若干次后又回到原来的位置,说明没有可插入的位置
    				
    					count++;
    				}
    				else if(destnum==fuben)
    				{
    					cout<<key[i]<<"在表中没有合适的插入位置"<<endl;
    				}
    				else
    					;		//否则什么都不做
    			}
    			//while循环之后,说明找到了这个位置
    			dest[destnum]=key[i];
    
    		}
    		
    	}
    
    }
    

     哈希函数中很重要的一个部分就是冲突处理函数,这里写出最常用的两个处理方法,线性探查再散列法和二次探查再散列法:

    算法的代码如下:

    int HashT::HashLinearPro(int H0,int i,int mod)
    {
    	int destnum;
    	destnum=(H0+i)%mod;
    	return destnum;
    }
    
    int HashT::HashQuadraticPro(int me,int H0,int mod,int flag)	
    {
    	int destnum;
    	if(flag%2==1)
    	{
    		destnum=(H0+me*me)%mod;	//这里的i应该为me
    	}
    	else
    	{
    		destnum=(H0-me*me)%mod;
    	}
    	return destnum;
    }
    

     二次探查再散列法,需要设置征服号,这里设置一个flag值,进行判断。

  • 相关阅读:
    LeetCode 230. Kth Smallest Element in a BST
    LeetCode 114. Flatten Binary Tree to Linked List
    LeetCode 222. Count Complete Tree Nodes
    LeetCode 129. Sum Root to Leaf Numbers
    LeetCode 113. Path Sum II
    LeetCode 257. Binary Tree Paths
    Java Convert String & Int
    Java Annotations
    LeetCode 236. Lowest Common Ancestor of a Binary Tree
    LeetCode 235. Lowest Common Ancestor of a Binary Search Tree
  • 原文地址:https://www.cnblogs.com/fistao/p/3006974.html
Copyright © 2011-2022 走看看