问题描述:针对某个单位电话号码簿,设计一个哈希表,并完成相应的建表和查表程序。 基本要求:设每个记录有下列数据项:电话号码、用户名、住址。从键盘输入各记录,以用户名为关键字建立哈希表,哈希函数用除留取余数法构造,采用线性探测法解决冲突。可以插入、查找、删除并显示给定用户名的记录,并计算查找长度, 哈希表保存到文件中。提将电话号码薄以文件形式保存到盘上,能够按用户名和电话号码两种形式建立哈希表并实现插入、查找、删除表中元素的功能。 测试数据:取某个单位电话号码簿中的30 个记录。
时间: 2024-02-01 12:15:28 浏览: 158
设计哈希表实现电话号码查询系统。
3星 · 编辑精心推荐
这是一个比较完整的程序设计任务,需要涉及到哈希表的设计和实现、文件的读写操作等。下面是一个可能的解答:
1. 哈希表的设计
我们需要设计一个哈希表来存储电话号码簿中的记录。由于要以用户名作为关键字建立哈希表,我们可以用用户名的哈希值来确定记录在哈希表中的位置。具体地,我们可以使用除留取余数法来计算哈希值,即将用户名的 ASCII 码值相加再取余。如果发生冲突,我们可以采用线性探测法,即向后查找空槽位,直到找到一个空槽位或者遍历了整个哈希表。
每个记录包含三个数据项:电话号码、用户名、住址。我们可以定义一个结构体来表示每个记录:
```
typedef struct {
char phone[12]; // 电话号码
char name[20]; // 用户名
char address[50]; // 住址
} Record;
```
2. 哈希表的实现
我们可以定义一个哈希表结构体,包含哈希表的大小、存储记录的数组、以及一个指向哈希函数的函数指针。具体实现如下:
```
#define TABLE_SIZE 31
typedef unsigned int (*hash_func)(const char *);
typedef struct {
Record records[TABLE_SIZE];
hash_func hash;
} HashTable;
```
其中,`hash_func` 是一个指向哈希函数的函数指针类型,`hash` 是一个指向哈希函数的指针。
我们可以定义一个哈希函数 `hash_name` 来计算用户名的哈希值:
```
unsigned int hash_name(const char *name) {
unsigned int hash = 0;
while (*name) {
hash += *name;
name++;
}
return hash % TABLE_SIZE;
}
```
在实现哈希表的插入、查找和删除操作时,需要根据哈希值来确定记录在哈希表中的位置。如果该位置为空,则说明该用户名对应的记录不存在;否则,需要比较该位置上的记录的用户名和待操作的用户名是否相同,来确定是插入、查找还是删除操作。
插入操作的实现如下:
```
void insert_record(HashTable *table, const Record *record) {
unsigned int hash = table->hash(record->name);
while (table->records[hash].name[0] != '\0') {
hash = (hash + 1) % TABLE_SIZE; // 线性探测
}
table->records[hash] = *record;
}
```
查找操作的实现如下:
```
Record *find_record(HashTable *table, const char *name) {
unsigned int hash = table->hash(name);
while (table->records[hash].name[0] != '\0') {
if (strcmp(table->records[hash].name, name) == 0) {
return &table->records[hash];
}
hash = (hash + 1) % TABLE_SIZE; // 线性探测
}
return NULL;
}
```
删除操作的实现如下:
```
void delete_record(HashTable *table, const char *name) {
unsigned int hash = table->hash(name);
while (table->records[hash].name[0] != '\0') {
if (strcmp(table->records[hash].name, name) == 0) {
table->records[hash].name[0] = '\0'; // 将该位置上的记录删除
return;
}
hash = (hash + 1) % TABLE_SIZE; // 线性探测
}
}
```
3. 文件的读写操作
我们需要将哈希表保存到文件中,并从文件中读取哈希表。我们可以采用二进制文件的形式来保存哈希表,这样可以避免文本文件中换行符和空格等字符对数据的影响。
保存哈希表的实现如下:
```
void save_table(const HashTable *table, const char *filename) {
FILE *fp = fopen(filename, "wb");
fwrite(table, sizeof(HashTable), 1, fp);
fclose(fp);
}
```
读取哈希表的实现如下:
```
void load_table(HashTable *table, const char *filename) {
FILE *fp = fopen(filename, "rb");
fread(table, sizeof(HashTable), 1, fp);
fclose(fp);
}
```
4. 完整程序的实现
最后,我们可以将上述代码整合起来,实现一个完整的程序。具体实现如下:
```
#include <stdio.h>
#include <string.h>
#define TABLE_SIZE 31
typedef struct {
char phone[12]; // 电话号码
char name[20]; // 用户名
char address[50]; // 住址
} Record;
unsigned int hash_name(const char *name) {
unsigned int hash = 0;
while (*name) {
hash += *name;
name++;
}
return hash % TABLE_SIZE;
}
typedef unsigned int (*hash_func)(const char *);
typedef struct {
Record records[TABLE_SIZE];
hash_func hash;
} HashTable;
void insert_record(HashTable *table, const Record *record) {
unsigned int hash = table->hash(record->name);
while (table->records[hash].name[0] != '\0') {
hash = (hash + 1) % TABLE_SIZE; // 线性探测
}
table->records[hash] = *record;
}
Record *find_record(HashTable *table, const char *name) {
unsigned int hash = table->hash(name);
while (table->records[hash].name[0] != '\0') {
if (strcmp(table->records[hash].name, name) == 0) {
return &table->records[hash];
}
hash = (hash + 1) % TABLE_SIZE; // 线性探测
}
return NULL;
}
void delete_record(HashTable *table, const char *name) {
unsigned int hash = table->hash(name);
while (table->records[hash].name[0] != '\0') {
if (strcmp(table->records[hash].name, name) == 0) {
table->records[hash].name[0] = '\0'; // 将该位置上的记录删除
return;
}
hash = (hash + 1) % TABLE_SIZE; // 线性探测
}
}
void save_table(const HashTable *table, const char *filename) {
FILE *fp = fopen(filename, "wb");
fwrite(table, sizeof(HashTable), 1, fp);
fclose(fp);
}
void load_table(HashTable *table, const char *filename) {
FILE *fp = fopen(filename, "rb");
fread(table, sizeof(HashTable), 1, fp);
fclose(fp);
}
int main() {
HashTable table;
table.hash = hash_name;
memset(table.records, 0, sizeof(table.records));
// 从键盘输入记录
for (int i = 0; i < TABLE_SIZE; i++) {
Record record;
printf("请输入第%d个记录的电话号码、用户名、住址:\n", i+1);
scanf("%s %s %s", record.phone, record.name, record.address);
insert_record(&table, &record);
}
// 保存哈希表到文件
save_table(&table, "phonebook.dat");
// 从文件中读取哈希表
load_table(&table, "phonebook.dat");
// 根据用户名查找记录
char name[20];
printf("请输入要查找的用户名:\n");
scanf("%s", name);
Record *record = find_record(&table, name);
if (record != NULL) {
printf("电话号码:%s\n", record->phone);
printf("住址:%s\n", record->address);
} else {
printf("未找到该用户!\n");
}
// 根据用户名删除记录
printf("请输入要删除的用户名:\n");
scanf("%s", name);
delete_record(&table, name);
// 保存修改后的哈希表到文件
save_table(&table, "phonebook.dat");
return 0;
}
```
注意,这里只是一个简单的示例程序,实际应用中可能还需要考虑更多的情况,比如哈希表的扩容、数据的校验等。
阅读全文