A : 线性开型寻址
题目描述
要求
使用线性开型寻址实现
描述
给定散列函数的除数 D 和操作数 m,输出每次操作后的状态。
有以下三种操作:
- 插入 x,若散列表已存在 x,输出“Existed”,否则插入 x 到散列表中,输出所在的下标。
- 查询 x,若散列表不含有 x,输出“-1”,否则输出 x 对应下标。
- 删除 x,若散列表不含有 x,输出“Not Found”,否则输出删除 x 过程中移动元素的个数。
实验目的
1、掌握散列表结构的定义和实现。
2、掌握散列表结构的应用。
输入输出格式
输入:
第一行两个整数D,m。分别代表散列函数的除数D和操作数m。
接下来m行,每行两个整数opt和x,分别代表操作类型和操作数。
若opt为0,代表插入x;
若opt为1,代表查询x;
若opt为2,代表删除x。
输出:
按需输出。
数据结构与算法描述
先构造一个散列表类,插入函数先判断该数散列表中是否存在,如果不存在则从插入数的起始桶开始遍历,找到空桶后插入。
class hashTable {
private:
int divisor;//除数
int* table;//散列表
public:
hashTable(int thedivisor ) {
divisor = thedivisor;
table = new int[divisor];
for (int i = 0; i < divisor; i++) {//初始化为-1
table[i] = -1;
}
}
~hashTable() { delete[] table; }
void insert(int x);
void find(int x);
void deletes(int x);
};
void hashTable::insert(int x) {//插入
for (int i = 0; i < divisor; i++) {//是否存在
if (x == table[i]) {
cout << "Existed" << endl;
return;
}
}
int s;
s = x % divisor;//起始桶
int i = s;
do {
if (table[i] == -1) {//找到空桶插入,输出下标
table[i] = x;
cout << i << endl;
break;
}
else {
i = (i + 1) % divisor;
}
} while (i != s);
}
查询函数从输入数的起始桶开始编列判断是否有。
void hashTable::find(int x) {//查询
int s = x % divisor;//起始桶
int j = s;
int b = 0;//判断是否有x
do {
if (table[j] == x) {//有输出下标
cout << j << endl;
b = 1;
break;
}
else {
j = (j + 1) % divisor;
}
} while (j != s && table[j] != -1);
if (b==0) {//没有输出-1
cout << -1 << endl;
}
}
删除函数,先判断散列表中是否存在,如果存在将要删除的数改为-1,并记录删除的位置。从删除的位置的下一个开始循环遍历。如果遇到空桶则直接跳出循环,如果是一下几种情况则用continue结束本轮循环,进行下一个循环。(1)遍历到的数恰好在起始桶;(2)删除的遍历到的数的起始桶在删除空位之后,且遍历到的数位置在自己的起始桶之后;(3)遍历的位置在删除空位的前面,遍历的位置在删除数的起始桶前;(4)删除数的起始桶在删除的空位后,删除的空位在遍历的数前。
void hashTable::deletes(int x) {//删除
int s = x % divisor;//起始桶
int j = s;
int b = 0;//判断是否存在
do {
if (table[j] == x) {//如果存在删除x,即改为-1
table[j] = -1;
b = 1;
break;
}
else {
j = (j + 1) % divisor;
}
} while (j != s && table[j] != -1);
if (b==0) {//如果没有输出 "Not Found"
cout << "Not Found" << endl;
return;
}
s = j;//删除后的空位(-1处)
j = (j + 1) % divisor;//删除的下一个位置
int k = s;//删除数的下标
int sum = 0;
for (int i = j; i != (j + divisor-1)%divisor; i=(i+1)%divisor) {//从删除的下一个位置,遍历整个散列表
if (table[i] == -1) {//遇到空桶直接跳出循环
break;
}
int x2 = table[i];//遍历到的数
if (i == (x2 % divisor) || ((x2%divisor)> s)&&i> (x2 % divisor)) {
continue;//当该数恰好在起始桶||删除的遍历到的数的起始桶在删除空位之后,且x2在起始桶之后
}
else {
if ( i < s&& i>(x2 % divisor)) {
continue;//遍历的位置在删除空位的前面,遍历的位置在删除数的起始桶前
}
if ((x2 % divisor) > s && s > i) {
continue;//删除数的起始桶在删除的空位后,删除的空位在遍历的数前
}
int a = i;
sum++;//除了以上的情况都要移动所以++
while (table[(a + divisor-1) % divisor]!=-1 ) {
a = (a + divisor - 1) % divisor;//从i开始向前遍历,直到有空位置
}
table[(a + divisor - 1) % divisor] = x2;//移动到该空位置
table[i] = -1;//原位置改为空
s = i;//将删除后空的位置改为此处
}
}
cout << sum << endl;//循环结束输出统计的移动个数
}
除了以上几种情况都要移动,从遍历所在的位置一次向前找到空位插入,并将删除后的空位置改为此处被移动的原位置。整个循环结束后输出统计的移动的个数。
测试结果
完整代码(含注释)
#include<iostream>
using namespace std;
class hashTable {
private:
int divisor;//除数
int* table;//散列表
public:
hashTable(int thedivisor ) {
divisor = thedivisor;
table = new int[divisor];
for (int i = 0; i < divisor; i++) {//初始化为-1
table[i] = -1;
}
}
~hashTable() { delete[] table; }
void insert(int x);
void find(int x);
void deletes(int x);
};
void hashTable::insert(int x) {//插入
for (int i = 0; i < divisor; i++) {//是否存在
if (x == table[i]) {
cout << "Existed" << endl;
return;
}
}
int s;
s = x % divisor;//起始桶
int i = s;
do {
if (table[i] == -1) {//找到空桶插入,输出下标
table[i] = x;
cout << i << endl;
break;
}
else {
i = (i + 1) % divisor;
}
} while (i != s);
}
void hashTable::find(int x) {//查询
int s = x % divisor;//起始桶
int j = s;
int b = 0;//判断是否有x
do {
if (table[j] == x) {//有输出下标
cout << j << endl;
b = 1;
break;
}
else {
j = (j + 1) % divisor;
}
} while (j != s && table[j] != -1);
if (b==0) {//没有输出-1
cout << -1 << endl;
}
}
void hashTable::deletes(int x) {//删除
int s = x % divisor;//起始桶
int j = s;
int b = 0;//判断是否存在
do {
if (table[j] == x) {//如果存在删除x,即改为-1
table[j] = -1;
b = 1;
break;
}
else {
j = (j + 1) % divisor;
}
} while (j != s && table[j] != -1);
if (b==0) {//如果没有输出 "Not Found"
cout << "Not Found" << endl;
return;
}
s = j;//删除后的空位(-1处)
j = (j + 1) % divisor;//删除的下一个位置
int k = s;//删除数的下标
int sum = 0;
for (int i = j; i != (j + divisor-1)%divisor; i=(i+1)%divisor) {//从删除的下一个位置,遍历整个散列表
if (table[i] == -1) {//遇到空桶直接跳出循环
break;
}
int x2 = table[i];//遍历到的数
if (i == (x2 % divisor) || ((x2%divisor)> s)&&i> (x2 % divisor)) {
continue;//当该数恰好在起始桶||删除的遍历到的数的起始桶在删除空位之后,且x2在起始桶之后
}
else {
if ( i < s&& i>(x2 % divisor)) {
continue;//遍历的位置在删除空位的前面,遍历的位置在删除数的起始桶前
}
if ((x2 % divisor) > s && s > i) {
continue;//删除数的起始桶在删除的空位后,删除的空位在遍历的数前
}
int a = i;
sum++;//除了以上的情况都要移动所以++
while (table[(a + divisor-1) % divisor]!=-1 ) {
a = (a + divisor - 1) % divisor;//从i开始向前遍历,直到有空位置
}
table[(a + divisor - 1) % divisor] = x2;//移动到该空位置
table[i] = -1;//原位置改为空
s = i;//将删除后空的位置改为此处
}
}
cout << sum << endl;//循环结束输出统计的移动个数
}
int main() {
int d, m;
cin >> d >> m;
hashTable h(d);
for (int i = 0; i < m; i++) {
int opt, x;
cin >> opt >> x;
if (opt == 0) {
h.insert(x);
}
else if (opt == 1) {
h.find(x);
}
else if (opt == 2) {
h.deletes(x);
}
}
return 0;
}
B : 链表散列
题目描述
要求
使用链表散列方式
描述
给定散列函数的除数 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。
输出:
按需输出。
数据结构与算法描述
构造一个节点结构体,和一个节点类,散列表类。将一个链表类chain* table作为散列表的私有成员,方便调用。
struct chainNode {//节点
int element;
chainNode* next;
};
class chain {//链表类
private:
int listsize;//链表长度
chainNode* firstNode;//首节点
public:
chain() {
listsize = 0;
firstNode = NULL;
}
void insert(int val);
int seek(int val);
int erase(int val);
};
void chain::insert(int val) {//链表插入
if (listsize == 0) {//插入的第一个数
chainNode* newNode = new chainNode();
newNode->element = val;
newNode->next = firstNode;
firstNode = newNode;
}
else {
chainNode* p = firstNode;
while (p->next != NULL) {//找到最后节点
p = p->next;
}
chainNode* newNode = new chainNode();
newNode->element = val;
newNode->next = NULL;
p->next = newNode;
}
listsize++;
}
int chain::seek(int val) {//链表查找
chainNode* seekNode = firstNode;
while (seekNode != NULL && seekNode->element != val) {
seekNode = seekNode->next;
}
if (seekNode == NULL) {
return -1;//找不到返回-1
}
else {
return listsize;//找到返回链表长度
}
}
int chain::erase(int val) {//链表删除
if (firstNode->element == val) {//如果删除的是首节点
chainNode* c = firstNode;
firstNode = firstNode->next;
delete c;
listsize--;
return listsize;//返回删除后的链表长度
}
chainNode* deleteNode = firstNode;
while (deleteNode->next != NULL && deleteNode->next->element != val) {//找到删除节点的前一个节点
deleteNode = deleteNode->next;
}
if (deleteNode->next == NULL) {
return -1;//找不到返回-1
}
else {
chainNode* p = deleteNode->next;//要删除的节点
chainNode* q = p->next;//删除节点的下一个节点
deleteNode->next = q;
delete p;
listsize--;
return listsize;//返回删除后的链表藏毒
}
}
class hashChain {//散列表类
private:
chain* table;//链表
int divisor;//除数
public:
hashChain(int d) {
divisor = d;
table = new chain[divisor];
}
~hashChain() { delete[] table; }
void dinsert(int x);
void dfind(int x);
void deletes(int x);
};
在散列表类的插入函数中先找到桶的位置为s然后调用table[s]链表的查找函数,如果不存在再调用table[s]链表的插入函数。
void hashChain::dinsert(int x) {//插入
int s = x % divisor;
if (table[s].seek(x) != -1) {//如果已经存在
cout << "Existed" << endl;
return;
}
else {
table[s].insert(x);
}
}
散列表类的查询函数,先找到桶的位置为s然后调用table[s]链表的查找函数,如果存在则输出链表查找函数的返回值。
void hashChain::dfind(int x) {//查询
int s = x % divisor;
if (table[s].seek(x) == -1) {//如果不存在
cout << "Not Found" << endl;
}
else {
cout << table[s].seek(x) << endl;
}
}
在散列表类的删除函数中先找到桶的位置为s然后调用table[s]链表的查找函数,如果存在再调用table[s]链表的删除函数,并输出返回值。
void hashChain::deletes(int x) {//删除
int s = x % divisor;
if (table[s].seek(x) == -1) {//如果不存在
cout << "Delete Failed" << endl;
}
else {
cout << table[s].erase(x) << endl;
}
}
测试结果
完整代码(含注释)
#include<iostream>
using namespace std;
struct chainNode {//节点
int element;
chainNode* next;
};
class chain {//链表类
private:
int listsize;//链表长度
chainNode* firstNode;//首节点
public:
chain() {
listsize = 0;
firstNode = NULL;
}
void insert(int val);
int seek(int val);
int erase(int val);
};
void chain::insert(int val) {//链表插入
if (listsize == 0) {//插入的第一个数
chainNode* newNode = new chainNode();
newNode->element = val;
newNode->next = firstNode;
firstNode = newNode;
}
else {
chainNode* p = firstNode;
while (p->next != NULL) {//找到最后节点
p = p->next;
}
chainNode* newNode = new chainNode();
newNode->element = val;
newNode->next = NULL;
p->next = newNode;
}
listsize++;
}
int chain::seek(int val) {//链表查找
chainNode* seekNode = firstNode;
while (seekNode != NULL && seekNode->element != val) {
seekNode = seekNode->next;
}
if (seekNode == NULL) {
return -1;//找不到返回-1
}
else {
return listsize;//找到返回链表长度
}
}
int chain::erase(int val) {//链表删除
if (firstNode->element == val) {//如果删除的是首节点
chainNode* c = firstNode;
firstNode = firstNode->next;
delete c;
listsize--;
return listsize;//返回删除后的链表长度
}
chainNode* deleteNode = firstNode;
while (deleteNode->next != NULL && deleteNode->next->element != val) {//找到删除节点的前一个节点
deleteNode = deleteNode->next;
}
if (deleteNode->next == NULL) {
return -1;//找不到返回-1
}
else {
chainNode* p = deleteNode->next;//要删除的节点
chainNode* q = p->next;//删除节点的下一个节点
deleteNode->next = q;
delete p;
listsize--;
return listsize;//返回删除后的链表藏毒
}
}
class hashChain {//散列表类
private:
chain* table;//链表
int divisor;//除数
public:
hashChain(int d) {
divisor = d;
table = new chain[divisor];
}
~hashChain() { delete[] table; }
void dinsert(int x);
void dfind(int x);
void deletes(int x);
};
void hashChain::dinsert(int x) {//插入
int s = x % divisor;
if (table[s].seek(x) != -1) {//如果已经存在
cout << "Existed" << endl;
return;
}
else {
table[s].insert(x);
}
}
void hashChain::dfind(int x) {//查询
int s = x % divisor;
if (table[s].seek(x) == -1) {//如果不存在
cout << "Not Found" << endl;
}
else {
cout << table[s].seek(x) << endl;
}
}
void hashChain::deletes(int x) {//删除
int s = x % divisor;
if (table[s].seek(x) == -1) {//如果不存在
cout << "Delete Failed" << endl;
}
else {
cout << table[s].erase(x) << endl;
}
}
int main() {
int D, m;
cin >> D >> m;
hashChain h(D);
for (int i = 0; i < m; i++) {
int opt, x;
cin >> opt >> x;
if (opt == 0) {
h.dinsert(x);
}
else if (opt == 1) {
h.dfind(x);
}
else if (opt == 2) {
h.deletes(x);
}
}
return 0;
}
标签:divisor,删除,int,开型,next,链表,table,散列
From: https://blog.csdn.net/Water_Star1/article/details/140566489