散列法的实验研究
【问题描述】
基本要求:设每个记录有下列数据项:电话号码、用户名、地址;从键盘输入各记录,分别以电话号码和用户名为关键字建立散列表;采用一定的方法解决冲突;查找并显示给定电话号码的记录;查找并显示给定用户名的记录。
进一步完成内容:
系统功能的完善:
设计不同的散列函数,比较冲突率;
在散列函数确定的前提下,尝试各种不同类型处理冲突的方法,考察平均查找长度的变化。
#include
#include
#include
using namespace std;
#define MAXSIZE 20
#define HASHSIZE 50 //定义表长
#define SUCCESS 1
#define UNSUCCESS -1
#include
typedef int Status;
int num1 = 0; //记录的个数
int num2 = 0;
//记录
typedef struct{
char name[MAXSIZE]; //姓名
char address[MAXSIZE]; //地址
char tel[MAXSIZE]; //电话号码
}DataType;
//HashTable1:以电话号码为关键字
typedef struct{
DataType *elem1[HASHSIZE]; //数据元素存储基址
int count1; //当前数据元素个数
int size1; //当前容量
}HashTable1;
//HashTable2:以姓名为关键字
typedef struct{
DataType *elem2[HASHSIZE]; //数据元素存储基址
int count2; //当前数据元素个数
int size2; //当前容量
}Hashtable2;
//比较两个数组是否相等,若相等返回1,否则返回-1
Status Compare(char a1[MAXSIZE], char a2[MAXSIZE]){
if(strcmp(a1, a2) == 0) return 1;
else return -1;
}
//遍历用户的信息
void ShowData(DataType *d){
system("cls");
cout << "姓名\t地址\t电话号码" << endl;
for(int i = 0; i < num1 + num2; i++){
if(!d[i].name[0] == '\0') //姓名非空时
cout<< d[i].name << "\t" << d[i].address << "\t" << d[i].tel << endl;
}
system("pause");
system("cls");
}
//一次探测
int Hash1(char name[MAXSIZE]){
int i = 0, p;
p = (int)name[0];
while(name[i] != '\0')
{
p += (int)name[i];
i++;
}
p = p % HASHSIZE;
return p;
}
int Hash2(char tel[MAXSIZE]){
int i, p = 0;
while(i != MAXSIZE){
p += (tel[i] - '0');
i++;
}
p = p % HASHSIZE;
return p;
}
//冲突处理函数
Status CollisionSolution(int p, int c){
int i, q;
i = c / 2 + 1;
while(i < HASHSIZE){
if(c % 2 == 0){
c++;
q = (p + i * i) % HASHSIZE;//倘若c为偶数,函数公式为:(余数+i*i)%表长,返回合理值
if(q >= 0) return q;
else i = c / 2 + 1;
}
else{
q = (p - i * i) % HASHSIZE;//若c为奇数,函数公式为:(余数-i*i)%表长,返回合理值
c++;
if(q >= 0) return q;
else i = c / 2 + 1;
}
}
return UNSUCCESS;
}
//以姓名为关键字,建立相应的哈希表
void CreateHashTable1(HashTable1* H, DataType* a, int m){
int i, p = -1, c = 0, pp;
cout << "以姓名为关键字建立哈希表" << endl;
for(i = 0; i < m; i++){
c = 0; //记录冲突次数的变量
p = Hash1(a[i].name);
pp = p;
while(H->elem1[pp] != NULL){ //若不为空,即产生冲突,调用冲突处理函数
pp = CollisionSolution(p, c); //若哈希地址冲突,进行冲突处理
c++;
if(pp < 0){
cout << "第" << i + 1 << "个记录无法解决冲突" << endl;
continue; //无法解决冲突,跳入下一循环
}
}
H->elem1[pp] = &(a[i]); //求得哈希地址,将信息存入
H->count1++; //表当前数据个数+1
cout << "第" << i + 1 << "个记录冲突次数为" << c << endl;
}
}
//以电话号码为关键字,建立相应的哈希表
void CreateHashTable2(Hashtable2* H, DataType* a, int m){
int i, p = -1, c = 0, pp;
cout << "以电话号码为关键字建立哈希表" << endl;
for(i = 0;i < m; i++){
c = 0; //记录冲突次数的变量
p = Hash2(a[i].tel);
pp = p;
while(H->elem2[pp] != NULL){ //若不为空,即产生冲突,调用冲突处理函数
pp = CollisionSolution(p, c); //若哈希地址冲突,进行冲突处理
c++;
if(pp < 0){
cout << "第" << i + 1 << "个记录无法解决冲突" << endl;
continue; //无法解决冲突,跳入下一循环
}
}
H->elem2[pp] = &(a[i]); //求得哈希地址,将信息存入
H->count2++; //表当前数据个数+1
cout << "第" << i + 1 << "个记录冲突次数为" << c << endl;
}
}
//创建通讯录
void Create(HashTable1* H1, DataType* a,Hashtable2* H2) //创建新的通讯录
{
system("CLS");
memset(a->tel,0,sizeof(a->tel));
cout << "输入要添加的个数:";
cin>> num1;
for(int i = 0; i < num1; i++){ //输入创建的用户信息
cout << "请输入第" << i + 1 << "个记录的姓名:";
cin>> a[i].name;
cout << "请输入第" << i + 1 << "个记录的地址:";
cin>> a[i].address;
cout << "请输入第" << i + 1 << "个记录的电话号码:";
cin>> a[i].tel;
}
cout << "添加成功" << endl;
CreateHashTable1(H1, a, num1);
CreateHashTable2(H2, a, num1);
system("pause");
system("cls");
}
//增加新的通讯录记录
void AddData(DataType* a, DataType *b, HashTable1* H1, Hashtable2* H2){
system("cls");
memset(b->tel, 0, sizeof(b->tel));
cout << "请输入要添加的个数:";
cin>> num2;
for(int i = 0; i < num2; i++){ //输入创建的用户信息
cout << "请输入第" << i + 1 << "个记录的姓名:";
cin>> b[i].name;
for(int j = 0; j < MAXSIZE; j++){
a[i + num1].name[j] = b[i].name[j];
}
cout << "请输入第" << i + 1 << "个记录的地址:";
cin>> b[i].address;
for(int j = 0; j < MAXSIZE; j++){
a[i + num1].address[j] = b[i].address[j];
}
cout << "请输入第" << i + 1 << "个记录的电话号码:";
cin>> b[i].tel;
for(int j = 0; j < MAXSIZE; j++){
a[i + num1].tel[j] = b[i].tel[j];
}
}
cout << "添加成功" << endl;
CreateHashTable1(H1, b, num2);
CreateHashTable2(H2, b, num2);
system("pause");
system("cls");
}
//在通讯录里查找姓名关键字,c用来记录冲突次数,若查找成功,显示信息
void Search(HashTable1* H1, DataType *a, Hashtable2* H2){
int i;
int c = 0;
int p, pp;
char NAME[20]; //定义要查找的名字的字符数组
system("cls");
int l;
cout << "1.按姓名查找" << endl;
cout << "2.按电话号码查找" << endl;
cout << "请输入你的选项:";
cin>> l;
switch(l){
case 1:
do{
cout << "请输入要查找记录的姓名:";
cin>> NAME;
p = Hash1(NAME); //调用一次探测函数
pp = p;
while((H1->elem1[pp] != NULL) && (Compare(NAME, H1->elem1[pp]->name) == -1)){
pp = CollisionSolution(p, c); //倘若一探测结果和所要查找的结果不同,调用二次探测函数
c++; //冲突次数增加
}
if(H1->elem1[pp] != NULL && Compare(NAME, H1->elem1[pp]->name) == 1){//探测到结果后将信息输出
cout << "姓名:" << H1->elem1[pp]->name << endl;
cout << "地址:" << H1->elem1[pp]->address << endl;
cout << "电话号码:" << H1->elem1[pp]->tel << endl;
cout << "查找过程冲突次数为" << c << endl;
}
else cout << "无此记录" << endl;
cout << "是否继续查找?1.继续 0.退出" << endl;
cin>> i;
}while(i != 0);
system("pause");
system("cls");
break;
case 2:
do{
memset(NAME, 0, sizeof(NAME)); //初始化
cout << "请输入要查找记录的电话号码:";
cin>> NAME;
p = Hash2(NAME); //调用一次探测函数
pp=p;
while((H2->elem2[pp] != NULL) && (Compare(NAME, H2->elem2[pp]->tel) == -1)){
pp = CollisionSolution(p, c); //倘若一探测结果和所要查找的结果不同,调用二次探测函数
c++; //冲突次数增加
}
if(H2->elem2[pp] != NULL && Compare(NAME, H2->elem2[pp]->tel) == 1){ //探测到结果后将信息输出
cout << "姓名:" << H2->elem2[pp]->name << endl;
cout << "地址:" << H2->elem2[pp]->address << endl;
cout << "电话号码:" << H2->elem2[pp]->tel << endl;
cout << "查找过程冲突次数为" << c << endl;
}
else cout << "无此记录" << endl;
cout << "是否继续查找?1.继续 0.退出" << endl;
cin>> i;
}while(i != 0);
system("cls");
break;
default:
break;
}
}
//在通讯录里修改某人信息
void Modify(HashTable1 *H1, DataType* a){
int p, pp;
char NAME[20]; //想要修改的姓名数组
system("cls");
cout << "请输入你所要修改的原用户名:";
cin>> NAME;
p = Hash1(NAME); //调用一次探测函数
pp = p;
while((H1->elem1[pp] != NULL) && (Compare(NAME, H1->elem1[pp]->name) == -1))
pp = CollisionSolution(p, 0); //倘若一探测结果和所要查找的结果不同,调用二次探测函数
if(H1->elem1[pp] != NULL && Compare(NAME, H1->elem1[pp]->name) == 1){ //探测到结果后修改信息
int m;
do{
cout << "修改信息" << endl;
cout << "1.修改姓名" << endl;
cout << "2.修改地址" << endl;
cout << "3.修改电话号码" << endl;
cout << "请选择你想要选择的选项,输入0结束修改此用户信息" << endl;
cin>> m;
if(m == 1){
int p, n=0, m, i;
cout << "请输入修改后记录的姓名:";
cin>> H1->elem1[pp]->name;
char t[20];
for(int i = 0; i < MAXSIZE; i++){
t[i] = H1->elem1[pp]->name[i];
}
p = Hash1(t);
m = p;
while(H1->elem1[m] != NULL){//若不为空,即产生冲突,调用冲突处理函数
m = CollisionSolution(p, n); //若哈希地址冲突,进行冲突处理
n++;
if(m < 0){
cout << "冲突无法解决" << endl;
break;
}
}
H1->elem1[m] = H1->elem1[pp]; //求得哈希地址,将信息存入
}
if(m == 2){
cout << "请输入修改后记录的地址:";
cin>> H1->elem1[pp]->address;
}
if(m == 3){
cout << "请输入修改后记录的电话号码:";
cin>> H1->elem1[pp]->tel;
}
}while(m != 0);
cout << "修改成功" << endl;
}
else cout << "此人不存在,修改不成功!" << endl;
system("CLS");
}
//在通讯录里查找姓名关键字,若查找成功,显示信息然后删除
void Delete(HashTable1* H1, DataType* a){
int i;
do{
int m, p, pp;
char NAME[20];
m = 0;
system("cls");
cout << "请输入要删除记录的姓名:";
m++;
cin>> NAME;
p = Hash1(NAME);
pp = p;
while((H1->elem1[pp] != NULL) && (Compare(NAME, H1->elem1[pp]->name) == -1))
pp = CollisionSolution(p, 0); //倘若一探测结果和所要查找的结果不同,调用二次探测函数
if(H1->elem1[pp] != NULL && Compare(NAME, H1->elem1[pp]->name) == 1){//探测到结果后删除信息
for(int i = 0; i < num1 + num2; i++){
if(Compare(NAME, a[i].name) == 1) a[i].name[0] = '\0';
}
H1->elem1[pp]->name[0] = '\0';//将所要删的用户的电话号码清空
H1->elem1[pp]->address[0] = '\0';
H1->elem1[pp]->tel[0] = '\0';
cout << "删除成功" << endl;
}
else cout << "此人不存在,删除不成功!" << endl;
cout << "是否继续删除?1.继续0.退出" << endl;
cin>> i;
}while(i != 0);
system("cls");
}
int main(){
int c, i = 0;
DataType a[MAXSIZE];
DataType b[MAXSIZE];
HashTable1 *H1;
Hashtable2 *H2;
H1 = (HashTable1*)malloc(sizeof(HashTable1)); //申请空间
for(i = 0; i < HASHSIZE; i++){ //初始化哈希表
H1->elem1[i] = NULL;
H1->size1 = HASHSIZE;
H1->count1 = 0;
}
H2 = (Hashtable2*)malloc(sizeof(Hashtable2)); //申请空间
for(i = 0; i < HASHSIZE; i++){ //初始化哈希表
H2->elem2[i] = NULL;
H2->size2 = HASHSIZE;
H2->count2 = 0;
}
while (1){
int m;
cout << "*****************************通讯录******************************" << endl;
cout << "* 【1】. 创建通讯录 *" << endl;
cout << "* 【2】. 添加用户信息 *" << endl;
cout << "* 【3】. 显示所有用户信息 *" << endl;
cout << "* 【4】. 查找用户信息 *" << endl;
cout << "* 【5】. 删除用户信息 *" << endl;
cout << "* 【6】. 修改用户信息 *" << endl;
cout << "* 【7】. 退出程序 *" << endl;
cout<< "*****************************************************************" << endl;
cout << "请输入操作序号:";
cin>> m;
switch(m){
case 1:
Create(H1, a, H2);
break;
case 2:
AddData(a, b, H1, H2) ;
break;
case 3:
ShowData(a);
break;
case 4:
c = 0;
Search(H1, a, H2);
break;
case 5:
Delete(H1, a);
break;
case 6:
c = 0;
Modify(H1, a);
break;
case 7:
return 0;
break;
default:
cout << "输入错误,请重新输入!" << endl;
}
}
system("pause");
return 0;
}