POJ 3349 哈希表

考察Hash算法。

两种方式:1.链地址法。 2.开放定址法。


1.链地址法。

优点:

         1.各链表上的结点是动态申请的,故更适合于造表前无法确定表长的情况。


缺点:1.动态申请结点,new操作非常耗时。

            2.指针域比较浪费空间。

解题思路:

               利用Hash法,链地址法解决冲突。

          key=( len1+len2+len3+len4+len5+len6)%prime

           =( len1%prime +len2%prime +len3%prime +len4%prime +len5%prime +len6)%prime

          为了避免出现大数,这里使用了同余模定理求key

注意,这里的key千万不能用平方和,本来这题时间就很紧凑了,乘法运算更加严重浪费时间,所以采用了连加求key,只要prime足够大,同样能够把地址冲突降低到最低,我取了10n(就是100W)内的最大的素数作为prime,   prime=999983


#include<iostream>
using namespace std;

//***********常量定义*****************//
const __int64 MAX=10000001;
const __int64 prime=999983;

//**********题目变量*****************//
struct Node
{
	__int64 len[6];//存储雪花六边的长度
};
Node leaf[MAX];//存储输入的雪花数据

class HashTable
{
public:
	   Node snow;
	   HashTable* next;
	   HashTable()
	   {
		   next=NULL;
	   }
};
HashTable*	Hash[prime+1];
//计算第K个雪花的Hash值
__int64 CmputeKey(int k)
{
	__int64 key=0;
	for(int i=0;i<6;i++)
	{
		key+=(leaf[k].len[i])%prime;
		key%=prime;
	}
	++key;
	return key;//键值后移1位,把key的范围从0~999982变为 1~999983  
}
//比较两片雪花顺时针方向是否相同
bool clockwise(HashTable*p,int k)
{
	bool flag=true;
	for(int j=0;j<6;j++)
	{
		flag=true;
		for(int i=0;i<6;i++)
		{
			if(leaf[k].len[i]!=p->snow.len[(i+j)%6])
			{
				flag=false;
				break;
			}
		}
		if(flag)
	    return true;
	}
	return false;
}
//比较两片雪花逆时针方向是否相同
bool countclockwise(HashTable*p,int k)
{
	bool flag=true;
	for(int j=0;j<6;j++)
	{
		flag=true;
		for(int i=0;i<6;i++)
		{
			if(leaf[k].len[i]!=p->snow.len[(11-i-j)%6])
			{
				flag=false;
				break;
			}
		}
		if(flag)
	    return true;
	}
	return false;
}
//处理第k个结点
bool process(int k)
{  
	bool flag=false;
	__int64 key;
	key=CmputeKey(k);
	//若Hash[Key]为NULL;
	if(!Hash[key])
	{
		HashTable* temp=new HashTable;
		for(int j=0;j<6;j++)
			temp->snow.len[j]=leaf[k].len[j];
		Hash[key]=temp;
	}
	else
	{
		HashTable* current=Hash[key];
		HashTable* tail=NULL;
		while(current)
		{
			if(clockwise(current,k)||countclockwise(current,k))
			{
				printf("%s","Twin snowflakes found.");
				flag=true;
				return flag;
			}
			else
			{
				tail=current;
				current=current->next;
			}
		}
		HashTable* temp=new HashTable;
		for(int j=0;j<6;j++)
		{
			temp->snow.len[j]=leaf[k].len[j];
		}
		tail->next=temp;
	}
	return flag;
}
int main()
{
	int N;//输入的数据
	bool flag;
	scanf("%d",&N);
	memset(Hash,0,sizeof(Hash));
	//采集数据
	for(int i=1;i<=N;i++)
	{
		for(int j=0;j<6;j++)
			scanf("%d",&leaf[i].len[j]);
	}
	for(int i=1;i<=N;i++)
	{
		flag=process(i);

		if(flag)
		return 0;
	}
    printf("%s","No two snowflakes are alike.");
}

比较两片雪花是否相等:

设定雪花A,B。

A不动,B旋转6次,A跟B分别比较2*6次;分别是正向相等,和反向相等

正向相等:

A0==B0,A1==B1,......A5==B5;

反向相等:

A0==B5,A1==B4...........A5==B0

//比较两片雪花顺时针方向是否相同
bool clockwise(HashTable*p,int k)
{
	bool flag=true;
	for(int j=0;j<6;j++)
	{
		flag=true;
		for(int i=0;i<6;i++)
		{
			if(leaf[k].len[i]!=p->snow.len[(i+j)%6])
			{
				flag=false;
				break;
			}
		}
		if(flag)
	    return true;
	}
	return false;
}
//比较两片雪花逆时针方向是否相同
bool countclockwise(HashTable*p,int k)
{
	bool flag=true;
	for(int j=0;j<6;j++)
	{
		flag=true;
		for(int i=0;i<6;i++)
		{
			if(leaf[k].len[i]!=p->snow.len[(11-i-j)%6])
			{
				flag=false;
				break;
			}
		}
		if(flag)
	    return true;
	}
	return false;
}


2.第二种方法

对于碰撞,采用开放地址发,省时间,也省空间,因为没有了new操作,也没有指针开销

第二种方法:在VS2010上运行没有问题,对10w个数据也可以正确运行,但是poj现实runtime error.请大家赐教



#include<iostream>
#include<algorithm>
#include<fstream>
using namespace std;
//*******************常量定义***************
const int MAX=100003;

//*******************算法变量****************
struct Node
{
 __int64 len[6];//存储六叶子
   bool  IsUsed;//是否已占用
};
Node Hash[MAX];//Hash表
__int64 snow[6];//存储输入的雪花
__int64 temp[6];
bool clockwise(__int64 leaf[6],__int64 k)
{ 
   bool flag;
   for(int j=0;j<6;j++)
   {
	   flag=true;
	   for(int i=0;i<6;i++)
	   {
		   if(Hash[k].len[i]!=leaf[(i+j)%6])
		   {
			   flag=false;
			   break;
		   }
	   }
	   if(flag)
		 return true;
   }
   return false;
}

bool countclockwise(__int64 leaf[6],__int64 k)
{
	bool flag;
	for(int j=0;j<6;j++)
	{
		flag=true;
		for(int i=0;i<6;i++)
		{
			if(Hash[k].len[i]!=leaf[(11-i-j)%6])
			{
				flag=false;
				break;
			}
		}
		if(flag)
		   return true;
	}
	return false;
}

bool SetUpHash(__int64 Array[6])
{
	int flag=false;
	for(int j=0;j<6;j++)
		temp[j]=Array[j];
	sort(Array,Array+6);
	__int64 Key=((Array[0]+Array[2]+Array[4])|(Array[1]+Array[3]+Array[5]))%MAX;
	if(!Hash[Key].IsUsed)//若该Key值对应的结点还未使用
	{
		for(int j=0;j<6;j++)
	    Hash[Key].len[j]=temp[j];

		Hash[Key].IsUsed=true;
	}
	else
	{
		int jump=1;
		while(Hash[Key].IsUsed)//当该结点被占用
		{
			if(clockwise(temp,Key)||countclockwise(temp,Key))
			{
					printf("%s","Twin snowflakes found.\n");
					return true;
			}
			else
			{
				Key=(Key+jump*jump)%MAX;
				jump++;
			}  
		}
		//找到空闲位置,插入元素
		for(int j=0;j<6;j++)
	    Hash[Key].len[j]=temp[j];

		Hash[Key].IsUsed=true;
	}
	return false; 
	
}

int main()
{
	for(int i=0;i<MAX;i++)
	   Hash[i].IsUsed=false;
	int N;//输入的雪花数
	int flag=false;
	/*scanf("%d",&N);*/
	fstream read("ceshi.txt");
	read>>N;
	for(int i=1;i<=N;i++)
	{   
		//输入雪花
		for(int j=0;j<6;j++)
		{
			/*scanf("%d",&snow[j]);*/
			read>>snow[j];
		}
		flag=SetUpHash(snow);
		if(flag)
		return 0;
	}
	printf("%s","No two snowflakes are alike.\n");
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值