哈希表应用(链地址法)

 

最近项目中碰到这么一个问题。
OPC客户端中存在已知点名的20000个点,其中点名是由字母和数字组成,比如PN110,PN112,PN113,PN114...PN200...PN900...
将DCS服务器中的20000个点加到OPC客户端中。如果遇到相同的点名,就不加入,不相同就加入。比如DCS服务器中有点PN110,PN111,则OPC客户端中只有一个PN110,一个PN111。
这里涉及到OPC客户端中的20000个点名跟DCS服务器的20000个点名进行比较问题,因为是工业自动化的问题,对实时性要求比较高,换句话说就是对比的时间复杂度要小才符合要求。

 

有些人会想到一般的比较方法,这个要花费几分钟时间。想到hash表,如果你对hash不是很了解,请看数据结构hash用在什么场合,这里我就不总结了,实际上这个是非常重要的。

书上是这么说的:理想的情况是希望不经过任何比较,一次存取便能得到所查询记录,就必须在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和结构中唯一的存储位置相对应。

直接帖代码:

 

class CBranch
{
public:	
	CBranch()
	{
		m_tags.RemoveAll();
		m_nLayer = 0;
		m_pBranches = NULL;
	}
	
	~CBranch()
	{ 
		while( !m_tags.IsEmpty() )
			delete m_tags.RemoveTail();
		if (!m_pBranches)
		{
			delete []m_pBranches;
		}
		
	}
	void AddTag( CExTag* pTag )  {m_tags.AddTail(pTag);}	
	
    int         m_nLayer;
	ExTagList   m_tags;	
	CBranch*    m_pBranches;
};

void COPCServerView::OnOperatecheck() 
{
	// TODO: Add your command handler code here
	CMainFrame *pFrame = (CMainFrame*)GetParentFrame();
	COPCServerDoc *pDoc = (COPCServerDoc *) pFrame->GetActiveDocument();
 	CBranch brhTagList[256];
	UCHAR  uchTemp= 0;
	BOOL   bRet = FALSE;
	CExTag *pTagFind = new CExTag;
	pTagFind->m_strName = "AMMM";
	
	CreateHash(&brhTagList[0], 0);
	
	POSITION posC = pDoc->m_Root.m_Channels.GetHeadPosition();	
	while(posC)
	{
		CChannel* pChannel = pDoc->m_Root.m_Channels.GetNext(posC);
		POSITION posD = pChannel->m_Devices.GetHeadPosition();
		while(posD)
		{
			CDevice* pDevice = pChannel->m_Devices.GetNext(posD);
			POSITION posG = pDevice->m_Groups.GetHeadPosition();
			while(posG)
			{
				CGroup* pGroup = pDevice->m_Groups.GetNext(posG);
				POSITION posT = pGroup->m_Tags.GetHeadPosition();
				while(posT)
				{
					CExTag* pTag = pGroup->m_Tags.GetNext(posT);
					if (!pTag || pTag->m_strName.GetLength() < 0)
					{
						continue;
					}
					else if (pTag->m_strName.GetLength() == 1)
					{
						uchTemp = pTag->m_strName.GetAt(0);					
						brhTagList[uchTemp].AddTag(pTag);
						
					}
					else if(pTag->m_strName.GetLength() == 2)
					{
						UCHAR  uchTempFirst= 0;
						UCHAR  uchTempSecond = 0;
						uchTempSecond = pTag->m_strName.GetAt(0);
						uchTempFirst = pTag->m_strName.GetAt(1);					
						brhTagList[uchTempFirst].m_pBranches[uchTempSecond].AddTag(pTag);
					}
					else if(pTag->m_strName.GetLength() >= 3)
					{
						UCHAR  uchTempFirst= 0;
						UCHAR  uchTempSecond = 0;
						UCHAR  uchTempThird  = 0;
						int    nIndex = pTag->m_strName.GetLength();
						
						uchTempFirst = pTag->m_strName.GetAt(nIndex-1);
						uchTempSecond = pTag->m_strName.GetAt(nIndex-2);	
						uchTempThird  = pTag->m_strName.GetAt(nIndex-3);
						brhTagList[uchTempFirst].m_pBranches[uchTempSecond].m_pBranches[uchTempThird].AddTag(pTag);
						
					}
					
					
				}
			}
		}
	}
    BOOL bNotExist  =	CheckTagName(&brhTagList[0], pTagFind, FALSE );
	if (!bNotExist)
	{
		MessageBox("点名存在");
	}


BOOL COPCServerView::CreateHash(CBranch *pBranches, int nLayer)
{
	CBranch *pBrh = NULL;
	pBrh = pBranches;
	if (nLayer < 2)
	{
		
		for (int i = 0; i < 256; i++)
		{
			(pBrh+i)->m_pBranches = new CBranch[256];
			if (!(pBrh+i)->m_pBranches)
			{
				return FALSE;
			}
			CreateHash(&(pBrh+i)->m_pBranches[0], nLayer+1);			
		}
	}
	return TRUE;
}

关键字为取点名后面三位,比如PN1234,则取234,其中'2’对应ASCII值为0x50,一个unsigned char最大表示0-255,所以建hash表大小为256。利用冲突法中的链表地址法,建立三次hash表,每个链表中点分别对应256中情况。

 其中里面的逻辑问题说明CChannel(通道),CDevice(设备),CGroup(组),CExTag(标签),一个通道下面有多个设备,一个设备下有多个组,一个组有多个标签。

 

总结:hash表的问题关键在关键字的确定,hash表的创建(创建后给它赋值具体的内容),处理冲突。

最后代码是老同志写的,我只是理解了一下!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值