原创  一道关于hash表的笔试题 收藏

 题目如下:

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... ) | 编辑| 举报| 收藏

旧一篇:什么是window station | 新一篇:Windows访问控制模型(第一部分)

  • 发表评论
  • 评论内容:
  •  
Copyright © 2608
Powered by CSDN Blog