题目如下:
1. 目的
现有一张树形结构的节目表(类似于图1),各干结点为类型(体育、足球),叶子结点为节目名(足甲、足乙)。通过构造设计一个树结构,可以根据结点名查询这个树结构,以便快速获取相应的关系结点的名称。应该能够处理同样结构的其他节目表,不限于本表。
体育
足球
足甲
足乙
籃球
姚明
喬丹
文藝
電影
中国電影
日本電影
電視
綜藝
電視劇
#
图1
根据以上内容、需要编程实现以下的功能模块。
① 设计一个基于hash方法的概念关联结构,写入以上树形节目表的内容。
② 可以保存hash表和概念关联结构到二进制文件和从二进制文件中读取出来。保证读出来的hash表和概念关联结构是有效的,读出来的hash表的内容和概念关联结构的内容与保存前是完全一致的。
③ 根据结点名称查询这个概念关联结构,获取关系结点信息(父亲、兄弟、儿子)。
④ 再写一个测试程序,可以输入图1中的任何节点名作为查询名称。然后输出这个名称的关系节点信息(父节点名称和所有兄弟节点以及儿子节点的名称)。
2. 功能要求
2.1. 要求只遍历一次树形节目表(参照图1),就可以把树形节目表的数据写入这个概念关联结构。
2.2. 要求采用Hash表快速的构造概念关联结构。
2.3 采用hash表根据结点名称尽可能快的查询关系结点信息。
3. 环境条件
3.1. 编程语言不设限制.C,C++或Java等任选。
3.2. 构造概念关联结构及根据结点名称查询概念关联结构时,请使用Hash方法。
解题提示:
1. 在构造树的过程中要采用堆栈。
2. Hash重码处理。
3. 在一大块连续一维内存块中,存贮概念树。不能用二块以上内存块来存贮概念树(Hash表可以用另外内存块)。
4. 概念树中的各个节点是固定长度的数据结构。
5. 节点数据结构的field最少化。
6. 从Hash到概念树的索引,概念树各节点间的索引都不能用指针,要用int型的offset。
7. 概念树的内存块size超出时,要重新分配,分配策略自行决定。
8. 要妥善处理多个兄弟、多个儿子的情况,由于处理顺序是从上而下,所以要在还不知道兄弟及儿子总数下巧妙处理。
hash 函数:
unsigned short hash(char *str)
{
register unsigned short h;
register unsigned char *p;
for(h=0, p = (unsigned char *)str; *p ; p++)
h = 15 * h + *p;
return h;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
解题思路:
哈西表节点结构:
对应在概念树中的索引
父节点哈西值
下一个兄弟节点的哈西值
第一个子节点的哈西值
下一个应该被搜索的节点 (当前新节点的哈西值与正在被搜索的哈西值相同,但指向内容不同,则下一个被搜索的节点索引,这样可加快哈西表的创建速度)
创建树:
所需: 新节点哈西值 父节点哈西值(没有父节点则为0)
若父节点不为0,则根据父节点哈西值在哈西表中找到对应节点,若该节点未被设置,则出错。
根据新节点哈西值,在哈西表中找到对应节点
若:该节点已被设置
若该节点的下一搜索域不为空,则移动到该域指明的节点,直至移动到该域为空的节点,记为节点A。
顺序在哈西表中向下移动直至第一个未被占用的节点(可能有重新构建哈西表的情况)
在哈西表中找到对应节点后,设置对应的值。包括:在树中的索引,父节点在哈西表中的索引。第一个子节点设置为-1,表示尚未有子节点。第一个兄弟节点设置为-1,意义同前;将节点A的下一搜索域设置为当前节点的索引。
判断新节点是哪个节点的兄弟节点:
若父节点的第一个子节点尚未被设置,则设置为新节点哈西值。
若已设置:
根据该值在哈西表中找到该节点,则该节点与新节点为兄弟节点。若该节点的第一个兄弟节点未设置,则设置为新节点哈西值。
若已设置:
根据该值在哈西表中移动,直至找到兄弟节点尚未设置的节点。
将该节点的兄弟节点设置为新节点哈西值
查找:
结果:被查找节点的父节点,所有兄弟节点,所有子节点
所需: 被查找节点的哈西值
得到父节点:
根据被查找节点的哈西值在哈西表中找到对应节点,根据被查找的节点中所保存的父节点哈
西值,找到父节点在哈西表中的位置。
若该节点未被设置,则出错
得到兄弟节点:
根据父节点中所保存的第一个子节点的索引,在哈西表中找到该节点。则该节点为被查找节
点的兄弟节点。根据该节点的兄弟节点,找到下一节点,则为下一个兄弟节点,重复以上过
程直至所找到的节点的兄弟节点为空。
之后被查找节点的兄弟节点均可找到
得到子节点:
根据被查找节点的子节点在哈西表中找到对应的节点,之后的过程同得到兄弟节点的过程。
代码如下:
typedef struct _tagInfo
{
const TCHAR *szParentType; //父类型值
const TCHAR *szType; //类型值
} TABLEINFO;
typedef struct _tagHashNode
{
unsigned int uIndexInArray; //在类型数组中的索引
unsigned int uParentHash; //父节点的hash值
unsigned int u1stSiblingHash; //第一个兄弟节点的hash值
unsigned int u1stChildHash; //第一个字节点的hash值
unsigned int uNextSearchHash; //没有用到
} HASH_NODE;
class CHashTable
{
void CreateHashTable();
BOOL ExtendHashTable(UINT nNewSize);
void InsertIntoHashTable(UINT nTypeHash, UINT nParentHash, UINT uArrayIndex);
void RetrieveParentNodeInfo(UINT uHashValue);
void RetrieveChildNodeInfo(UINT uHashValue);
HASH_NODE **m_ppHashTable;
UINT m_uHashTableSize;
TABLEINFO *m_pInfoTable;
UINT m_uInfoTableSize;
}
void CHashTable::CreateHashTable()
{
for (UINT i = 0; i < m_uInfoTableSize; ++i)
{
UINT uParentHash = hash(m_pInfoTable[i].szParentType);
UINT uTypeHash = hash(m_pInfoTable[i].szType);
if (uTypeHash == 0)
continue;if (uTypeHash > m_uHashTableSize)
{
if (!ExtendHashTable(uTypeHash))
return;
}
InsertIntoHashTable(uTypeHash, uParentHash, i);
}
}
BOOL CHashTable::ExtendHashTable(UINT nNewSize)
{
HASH_NODE **ppTemp = new HASH_NODE * [nNewSize];
if (ppTemp == NULL)
return FALSE;
ZeroMemory(ppTemp, sizeof(HASH_NODE *)*nNewSize);
memcpy(ppTemp, m_ppHashTable, sizeof(HASH_NODE *) * m_uHashTableSize);
delete [] m_ppHashTable;
m_ppHashTable = ppTemp;
m_uHashTableSize = nNewSize;
return TRUE;
}
void CHashTableDlg::InsertIntoHashTable(UINT uTypeHash, UINT uParentHash,
UINT uArrayIndex)
{
if (uTypeHash > m_uHashTableSize || uParentHash > m_uHashTableSize)
return;
UINT uTypeIndex = uTypeHash - 1;
while (m_ppHashTable[uTypeIndex] != NULL) // this node has been occupied, then
{ // walk the table until a available
uTypeIndex++; // node is occurred
}
m_ppHashTable[uTypeIndex] = new HASH_NODE;
if (m_ppHashTable[uTypeIndex] == NULL)
return;
ZeroMemory(m_ppHashTable[uTypeIndex], sizeof(HASH_NODE));
m_ppHashTable[uTypeIndex]->u1stChildHash = 0;
m_ppHashTable[uTypeIndex]->uIndexInArray = uArrayIndex;
if (uParentHash == 0)
return;
UINT uParentIndex = uParentHash - 1;
m_ppHashTable[uTypeIndex]->uParentHash = uParentIndex;
if (m_ppHashTable[uParentIndex]->u1stChildHash == 0)
{
m_ppHashTable[uParentIndex]->u1stChildHash = uTypeIndex;
}
else
{
UINT uPresilbing = m_ppHashTable[uParentIndex]->u1stChildHash;
while (m_ppHashTable[uPresilbing]->u1stSiblingHash)
uPresilbing = m_ppHashTable[uPresilbing]->u1stSiblingHash;
if (uPresilbing < m_uHashTableSize)
m_ppHashTable[uPresilbing]->u1stSiblingHash = uTypeIndex;
}
}
void CHashTable::RetrieveParentNodeInfo(UINT uHash)
{
if (uHash > m_uHashTableSize || m_ppHashTable[uHash] == NULL)
return;
std::list<UINT> parentList;
UINT uParentIndex = m_ppHashTable[uHash]->uParentHash;
while (uParentIndex)
{
UINT uArrayIndex = m_ppHashTable[uParentIndex]->uIndexInArray;
parentList.push_back(uArrayIndex);
uParentIndex = m_ppHashTable[uParentIndex]->uParentHash;
}
std::list<UINT>::reverse_iterator ritor = parentList.rbegin();
for (; ritor != parentList.rend(); ++ritor)
{
UINT uIndex = (*ritor);
m_pInfoTable[uIndex].szType;
uIndex++;
}
}
void CHashTable::RetrieveChildNodeInfo(UINT uHashIndex)
{
if (uHashIndex > m_uHashTableSize || m_ppHashTable[uHashIndex] == NULL)
return;
const TCHAR *s = m_pInfoTable[m_ppHashTable[uHashIndex ]->uIndexInArray].szType;
UINT uChildIndex = m_ppHashTable[uHashIndex]->u1stChildHash;
while (uChildIndex && m_ppHashTable[uChildIndex])
{
s = m_pInfoTable[m_ppHashTable[uChildIndex]->uIndexInArray].szType;
RetrieveChildNodeInfo(uChildIndex);
uChildIndex = m_ppHashTable[uChildIndex ]->u1stSiblingHash;
}
}
void CHashTable::RetrieveNodeInfo(const TCAR *szType);
{
UINT uHash = hash (szType);
UINT uHash = hash(strType.GetBuffer());
RetrieveParentNodeInfo(uHash - 1); // using hash value as index of Hash Table
RetrieveChildNodeInfo(uHash - 1);
}
发表于 @ 2008年02月01日 15:25:00 | 评论( loading... ) | 举报| 收藏