C++学习:散列-开放定址法
#include <algorithm>
#include <math.h>
#include <iostream>
using namespace std;
#define MAXTABLESIZE 100000 // 允许开辟的最大散列列表长度
typedef int ElementType; // 关键词类型,使用整型
typedef int Index; // 散列地址类型
typedef Index Position; // 数据所在位置与散列地址是同一类型
// 散列单元状态类型,分别对应:有合法元素、空单元、有已删除元素
typedef enum {Legitimate, Empty, Delete} EntryType;
typedef struct HashEntry Cell; // 散列表单元类型
struct HashEntry {
ElementType Data; // 存放元素
EntryType Info; // 单元状态
};
typedef struct TblNode * HashTable; // 散列表类型
struct TblNode {
int TableSize; // 散列表的最大长度
int CurrentSize; // 当前表长
Cell* Cells; // 存放散列单元的指针
};
int NextPrime(int N) {
// 返回大于等于N且不超过MAXTABLESIZE的最小素数
int i, p=(N%2)?N :N+1; // 从大于N的下一个奇数开始,因为素数除了2都是奇数
while (p <= MAXTABLESIZE) {
for (i = (int)sqrt(p); i>1; i--)
if(!(p%i)) break; // p不是素数
if (i == 1) break; // for正常结束,说明p是素数
else p+=2;
}
return p;
}
HashTable CreatTable(int N) {
// 创建散列表
int i;
int TableSize = NextPrime(N);
HashTable H = (HashTable)malloc(sizeof(struct TblNode));
H->TableSize = TableSize; // 保证散列表最大长度是素数
H->CurrentSize = 0;
H->Cells = (Cell *)malloc(H->TableSize * sizeof(Cell)); // 声明单元数组
// 初始化单元格状态为空单元
for(i = 0; i < H->TableSize; i++)
H->Cells[i].Info = Empty;
return H;
}
Position Hash(ElementType key, int TableSize) {
// 哈希函数
return key % TableSize;
}
Position Find(HashTable H, ElementType Key) {
// 平方探测法查找元素,返回Pos
Position CurrentPos, NewPos; // CurrentPos为初始位置,NewPos为冲突后的新位置
int Count = 0; // 记录冲突次数
NewPos = CurrentPos = Hash(Key, H->TableSize); // 初始化查找位置
// 当查找位置为非空,且不是要查找的元素时,发生冲突,注意,查找只是按按Key查找,不是插入,插入可以覆盖Delete
// 就算找到已删除的元素并返回它的位置,但此时单元格仍是Delete,还认为此位置是空位置,固后续可插入
while (H->Cells[NewPos].Info == Legitimate && H->Cells[NewPos].Data != Key) {
// 统计一次冲突,并判断奇偶次
// 冲突次数+1
if (++Count % 2) { // 奇数次冲突
// 增量为 ((Count+1)/2)^2
NewPos = CurrentPos + (Count+1)*(Count+1)/4;
// 注意调整为合法地址
if (NewPos >= H->TableSize) NewPos %= H->TableSize;
}else { // 偶数次冲突
// 增量为 -(Count/2)^2
NewPos = CurrentPos - Count*Count/4;
// 注意调整为合法地址
while (NewPos < 0) NewPos += H->TableSize;
}
}
// 否则找到Key
// 或者找不到,但返回一个空位置(含Delete)
return NewPos;
}
bool Insert(HashTable H, ElementType Key) {
// 平方探测法插入函数
if (H->CurrentSize == H->TableSize) {
cout << "表满,插入失败" << endl;
return false;
}
Position Pos = Find(H, Key); // 先查找,若查找成功,返回单元格卫Legitimate则不用插入,若查找失败,非Legitimate,此时Pos为空位置或Delete元素
if (H->Cells[Pos].Info != Legitimate) { // 若键值为空或Delete,则可以插入在此
H->Cells[Pos].Info = Legitimate;
H->Cells[Pos].Data = Key;
cout << "插入的数据为:" << H->Cells[Pos].Data << endl;
H->CurrentSize ++; // 内存增加
return true; // 插入成功,返回true
}else {
// 若此时Info == Legitimate,则此单元格必定是Key,已经有Key了无需插入
cout << "键值 " << Key << " 已存在" << endl;
return false;
}
}
bool Detete(HashTable H, ElementType Key) {
// 删除Key操作
Position Pos = Find(H, Key);
if(H->Cells[Pos].Info == Legitimate) { // 如果找到了待删除的Key
H->Cells[Pos].Info = Delete; //标记为删除
H->CurrentSize --; // 内存减少
return true;
}
// key不存在
cout << "键值 " << Key << " 不存在" << endl;
return false;
}
void FreeHashTable(HashTable H) {
free(H->Cells);
free(H);
}
void PrintHashTable(HashTable H) {
cout << "\n---------- 散列表 ----------" << endl;
cout << "单元\t";
for (int i = 0; i < H->TableSize; i++) {
cout << i << '\t';
}
cout << "\n状态\t";
for (int i = 0; i < H->TableSize; i++) {
cout << H->Cells[i].Info << '\t';
}
cout << "\n数据\t";
for (int i = 0; i < H->TableSize; i++) {
if (H->Cells[i].Info == Empty)
cout << "-\t";
else
cout << H->Cells[i].Data << '\t';
}
cout << "\n容量\t" << H->CurrentSize << '/' << H->TableSize << endl;
}
int main(int argc, char *argv[]) {
int N, Command, Key, Pos;
cout << "N = ";
cin >> N;
HashTable H = CreatTable(N);
PrintHashTable(H);
while (true) {
cout << "指令\t1 key-插入key\t2 key-删除key\t3 key-查找key\t4-退出 : ";
cin >> Command;
switch (Command) {
case 1: // 插入
cin >> Key;
Insert(H, Key);
break;
case 2: // 删除
cin >> Key;
Detete(H, Key);
break;
case 3: // 查找
cin >> Key;
Pos = Find(H, Key);
if (H->Cells[Pos].Info == Legitimate) {
cout << Pos << endl;
}else {
cout << "Key " << Key <<" 不存在" << endl;
}
break;
case 4: // 清空并退出
FreeHashTable(H);
return 0;
default:
cout << "请正确输入有效指令!\n";
break;
}
PrintHashTable(H);
}
}
测试

1197

被折叠的 条评论
为什么被折叠?



