1.1 实验内容
假设散列表长为m,散列函数为H(x),用链地址法处理冲突。试编写输入一组关键字并建造散列表的算法。
解决冲突的另一种方法称为开散列方法(opcnhashing,也称为链地址法,separate chaining),在这种方法中,首先按数据元素的关键字用某一个散列函数计算出数据元素的存放位置。通过散列函数计算出来的具有相同地址的数据元素归于同一子集合。每一个子集合也称为一个桶。通常各个桶中的数据元素通过一个单链表链接起来,亦称为同义词子表,所有链表的表头结点组成一个向最。因此,向量的元素个数与可能的桶数相等。桶号为i的同义词子表的表头结点是向量中的第i个元素。
1.2文件结构、开发环境等说明
开发环境版本 | VisualStudio 2022 | 工程文件名 | hash_table.sln |
头文件个数 | 3个 | 源程序文件个数 | 1个 |
文件名 | 文件类型 | 功能简介 | 备注 |
OpenHashTable.h | 头文件 | 开散列表类类模板头文件,包括数据成员及成员函数的声明与定义 | |
Node.h | 头文件 | 结点类模板头文件,包括数据成员及成员函数的声明与定义 | |
Assistance.h | 头文件 | 辅助软件包 | |
text.cpp | 源文件 | 测试文件 |
1.3 实现技术
1、开散列表类和结点类
OpenHashTable.h文件中声明定义了开散列表类模板,Node.h文件中声明定义了结点类模板
开散列表类中的数据成员有二级Node型指针**ht和除留余数法的除数(在本题中就是表长m)。而结点类中的数据成员有数据域和指针域,数据域存放关键字,指针域存放指向单链表中的下一个结点,在一个单链表中的所有结点用散列函数H(x)计算出来的结果相同(在本题中用除留余数法的函数作为哈希函数)。
开散列表类:
template<class ElemType,class KeyType>
class OpenHashTable
{
protected:
//数据成员
Node<ElemType>** ht;//散列表
int m;//除留余数法的除数
//辅助函数
int H(KeyType key) const;//散列函数
public:
OpenHashTable(int divisor);
~OpenHashTable();
OpenHashTable(ElemType v[],int n, int divisor);
//void show();
};
结点类:
template <class ElemType>
struct Node
{
// 数据成员:
ElemType data; // 数据域
Node<ElemType>* next; // 指针域
// 构造函数:
Node(); // 无参数的构造函数
Node(ElemType item, Node<ElemType>* link = NULL); // 已知数数据元素值和指针建立结构
};
2、构造散列表
调用开散列表类中的构造函数来构造开散列表,先for循环将ht[i]都置NULL,表示在ht[i]不存在对应的单链表,即还未存储元素。再通过for循环,依次访问v[]数组中的每一个元素v[i],调用散列函数,将除留余数法的结果赋值给k,再new一个新的Node结点,并用v[i]初始化这个结点的数据域,将ht[k](指向单链表第一个结点的指针)赋值给p的next指针域,并将指向第一个结点的指针ht[k]指向p,至此完成一个结点的插入。后面的结点都采用头插法插入散列表中,直到所有元素都插入完毕。
template<class ElemType, class KeyType>
OpenHashTable<ElemType, KeyType>::OpenHashTable(ElemType v[],int n, int divisor)
{//根据数组v中的元素,divisor为除留余数法的除数构造一个散列表
int i, k;
Node<ElemType>* q;//Node型指针
m = divisor;//赋值除数
ht = new Node<ElemType>*[m];//分配元素存储空间
for (i = 0; i < m; i++)
ht[i] = NULL;
for (i = 0; i < n; i++)
{
k = H(v[i]);
q = new Node<ElemType>(v[i]);
q->next = ht[k];
ht[k] = q;
}
……
}
3、显示散列表
遍历整个散列表,将散列表形象地显示出来。
template<class ElemType, class KeyType>
OpenHashTable<ElemType, KeyType>::OpenHashTable(ElemType v[],int n, int divisor)
{//根据数组v中的元素,divisor为除留余数法的除数构造一个散列表
……
for (i = 0; i < n; i++)
{
cout << i << ": ";
if (ht[i] == NULL)
cout << endl;
else
{
//cout << ht[i]->data << " --> ";
Node<ElemType>* p;
p = ht[i];
while (p != NULL)
{
cout << p->data << " --> ";
p = p->next;
}
cout << "NULL"<<endl;
}
}
}
1.4 测试结果
1.4.1.1测试实例
int elem[] = { 19, 14, 23, 1, 68, 20, 84, 27, 55, 11, 10, 79 };
OpenHashTable<int, int>ht(elem, 12, 12);
1.4.1.2测试结果
1.4.1.2测试实例
int elem[] = { 22,76,53,49,88,2,36,75,45,42,25,29,20,38,41,43,70,73,66,63,64,69,100,121,136,532,786 };
OpenHashTable<int, int>ht(elem, 12, 12);
1.4.1.2测试结果
完整代码可看资源区
创作不易~麻烦点个赞~~谢谢大家~~~