实验8.2 链表散列
要求
使用链表散列方式
描述
给定散列函数的除数D和操作数m,输出每次操作后的状态。
有以下三种操作:
- 插入x,若散列表已存在x,输出"Existed"
- 查询x,若散列表不含有x,输出"Not Found",否则输出x所在的链表长度
- 删除x,若散列表不含有x,输出"Delete Failed",否则输出x所在链表删除x后的长度
格式
输入格式
第一行两个整数D(1<=D<=3000)和m(1<=m<=3000),其中D为散列函数的除数,m为操作数。
接下来的m行,每行两个整数opt和x,分别代表操作类型和操作数。
若opt为0,则代表向散列表中插入x;
若opt为1,代表查询散列表中x是否存在;
若opt为2,(如果散列表中含有x),删除x。
数据保证散列表不会溢出。
输出格式
按需输出。
思路与探讨
散列表线性探查
笔记补充——第十章:散列表,指路10.3 && 10.5.4
整体思路描述
- 主要是字典的链式描述,包括定义链节点,创建链表结构,实现插入,查询,删除等函数定义与实现。最后基于链表结构创建哈希,实现链式散列。
细节思路描述
sortedChain
部分
方法find
查询theKey,若散列表不含有theKey,输出"Not Found",否则输出theKey所在的链表长度
-
从第一个节点开始扫描节点,直到遇到第一个关键字大于等于theKey的节点currentNode或全部判断完为止
-
判断currentNode所指节点中数对的关键字是否等于theKey
currentNode->element.first =theKey
-
若相等,输出theKey所在的链表长度,否则返回Not Found
方法insert
插入x,若散列表已存在x,输出"Existed"
-
从第一个节点开始,寻找第一个关键字≥theKey的数对
-
若
p->element.first == theKey
-
若
p->element.first > theKey
-
新节点newNode ←(插入的数对thePair,p)
-
tp不为空:新节点插入到tp后面
tp->next= newNode
; -
tp为空:新节点为首节点
firstNode=newNode
;
-
-
dSize++
-
方法erase
删除x,若散列表不含有x,输出"Delete Failed",否则输出x所在链表删除x后的长度
hashChains
部分
查找(find):
-
计算起始桶号为
f(k) = k % D
;搜索该桶所对应的链表.table[hash(theKey) % divisor].find(theKey);
插入(insert):
-
计算
f(k)
;搜索;插入。 关注size判断。int homeBucket = (int)hash(thePair.first) % divisor; int homeSize = table[homeBucket].size(); table[homeBucket].insert(thePair); if (table[homeBucket].size() > homeSize) dSize++;
删除(erase):
-
计算
f(k)
;搜索;删除table[hash(theKey) % divisor].erase(theKey);
若已看懂思路,试着自己写~
实现代码
#include <iostream>
#include <string>
using namespace std;
template <class K> class Hash;
template<>
class Hash<int>
{//把类型k映射到一个非负整数
public:
size_t operator()(const int theKey) const
{
return size_t(theKey);
}
};
template<class K, class E>
class dictionary
{
public:
virtual ~dictionary() {}
//返回true,当且仅当字典为空
virtual bool empty() const = 0;
//返回字典中数对的数目
virtual int size() const = 0;
//返回匹配数对的指针
virtual pair<const K, E>* find(const K&) const = 0;
//删除匹配的数对
virtual void erase(const K&) = 0;
//往字典中插入一个数对
virtual void insert(const pair<const K, E>&) = 0;
};
template <class K, class E>
struct pairNode
{
pair<const K, E> element;
pairNode<K, E>* next;
pairNode(const pair<const K, E>& thePair):element(thePair){}
pairNode(const pair<const K, E>& thePair,pairNode<K, E>* theNext):element(thePair)
{next = theNext;}
};
template<class K, class E>
class sortedChain : public dictionary<K, E>
{
public:
sortedChain() { firstNode = NULL; dSize = 0; }
~sortedChain();
bool empty() const { return dSize == 0; }
int size() const { return dSize; }
//查询x,若散列表不含有x,输出"Not Found",否则输出x所在的链表长度
pair<const K, E>* find(const K& theKey) const;
//插入x,若散列表已存在x,输出"Existed"
void insert(const pair<const K, E>& thePair);
//删除x,若散列表不含有x,输出"Delete Failed",否则输出x所在链表删除x后的长度
void erase(const K& theKey);
protected:
pairNode<K, E>* firstNode;//指向链表第一个节点的指针
int dSize;//表中的数对个数
};
template<class K, class E>
sortedChain<K, E>::~sortedChain()
{//析构函数
while (firstNode != NULL)
{
pairNode<K, E>* nextNode = firstNode->next;
delete firstNode;
firstNode = nextNode;
}
}
template<class K, class E>
pair<const K, E>* sortedChain<K, E>::find(const K& theKey) const
{
pairNode<K, E>* currentNode = firstNode;
//搜索关键字为theKey的数对
while (currentNode != NULL &¤tNode->element.first != theKey)
currentNode = currentNode->next;
//判断是否匹配,若有找到输出x所在的链表长度
if (currentNode != NULL && currentNode->element.first == theKey)
{
cout << dSize <<endl;
}
//无匹配的数对,输出Not Found
else
{
cout<<"Not Found"<<endl;
}
}
template<class K, class E>
void sortedChain<K, E>::insert(const pair<const K, E>& thePair)
{//往字典中插入thePair,覆盖已经存在的匹配的数对
pairNode<K, E>* p = firstNode, * tp = NULL;//跟踪p
while (p != NULL && p->element.first < thePair.first)
{
tp = p;
p = p->next;
}
//检查是否有匹配的数对
//情况(1)有匹配的数对
if (p != NULL && p->element.first == thePair.first)
{//有就输出Existed
cout << "Existed" << endl;
return;
}
//情况(2)无匹配的数对,为thePair建立新节点
pairNode<K, E>* newNode = new pairNode<K, E>(thePair, p);
//在tp之后插入新节点
if (tp == NULL) firstNode = newNode;
else tp->next = newNode;
//因为插进来一个,所以数对数量++
dSize++;
return;
}
template<class K, class E>
void sortedChain<K, E>::erase(const K& theKey)
{
pairNode<K, E>* p = firstNode, * tp = NULL;
//搜索关键字为theKey的数对
while (p != NULL && p->element.first < theKey)
{
tp = p;
p = p->next;
}//tp就是追踪用的,刚好在p的前一个
//确定是否匹配
if (p != NULL && p->element.first == theKey)
{//找到一个匹配的数对,输出所在链表删除后的长度
if (tp == NULL) firstNode = p->next;
else tp->next = p->next;
delete p;
dSize--;
cout << dSize <<endl;
return;
}
//没找到就输出"Delete Failed"
cout << "Delete Failed" << endl;
}
template<class K, class E>
class hashChains : public dictionary<K, E>
{
public:
hashChains(int theDivisor = 11)
{
divisor = theDivisor;
dSize = 0;
table = new sortedChain<K, E>[divisor];
}
~hashChains() { delete[] table; }
bool empty() const { return dSize == 0; }
int size() const { return dSize; }
pair<const K, E>* find(const K& theKey) const
{//查找
table[hash(theKey) % divisor].find(theKey);
}
void insert(const pair<const K, E>& thePair)
{//插入
int homeBucket = (int)hash(thePair.first) % divisor;
int homeSize = table[homeBucket].size();
table[homeBucket].insert(thePair);
if (table[homeBucket].size() > homeSize)
dSize++;
}
void erase(const K& theKey)
{//删除
table[hash(theKey) % divisor].erase(theKey);
}
protected:
sortedChain<K, E>* table;
Hash<K> hash;
int dSize;
int divisor;
};
int main()
{
int D, m;
cin >> D >> m;
hashChains<int, int> a(D);
pair<int, int> q;
for (int i = 0; i < m; i++)
{
int opt, number;
cin >> opt >> number;
if (opt == 0)
{
q.first = number; q.second = number;
a.insert(q);
}
else if (opt == 1)
{
q.first = number; q.second = number;
a.find(q.first);
}
else
{
q.first = number; q.second = number;
a.erase(q.first);
}
}
return 0;
}