// El libro de referencia es la estructura de datos y el análisis de algoritmos de Machinery Industry Press (descripción en lenguaje C);
// Este programa es un programa de portabilidad, que utiliza una tabla hash implementada por el método de enlace separado;
// Controle la interfaz de impresión para que tenga un buen efecto de visualización;
// Puede compilar y ejecutar bajo Linux / Mac os / Windows;
// Si tiene alguna deficiencia, por favor menciónela, y el bloguero hará todo lo posible para modificarla;
// Si le resulta útil, por favor, recopile o comparta con otros;
// El plagio y la reimpresión sin permiso están estrictamente prohibidos;
// El código fuente está aquí, espero inspirarte;
// ------------------------------------------------ ----------------------------
//main.c
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "hashtable.h"
int get_first(void); //获取用户输入的第1个字符;
elemtype input(void); //处理错误输入;
void eatline(void); //清空输入缓冲区;
int show_menu(void); //提供散列表菜单选项;
void choice(int ch, hashtable *ht); //实现具体操作的函数;
int main(void)
{
int ch;
hashtable *table = initialize_table(TABLESIZE);
while ((ch = show_menu()) != 'q')
{
choice(ch, table);
}
destroy_table(table);
puts("欢迎下次使用!");
return 0;
}
int get_first(void)
{
int ch;
do
{
ch = tolower(getchar());
} while (isspace(ch));
eatline();
return ch;
}
elemtype input(void)
{
elemtype val;
printf("请输入一个元素值: ");
while (scanf("%d", &val) != 1)
{
eatline();
printf("输入有误!请重新输入: ");
}
eatline();
return val;
}
void eatline(void)
{
while (getchar() != '\n')
continue;
return;
}
int show_menu(void)
{
int ch;
puts("===============================");
puts(" 欢迎使用散列表菜单");
puts("a) 为散列表添加新元素");
puts("b) 删除散列表中的元素");
puts("c) 在散列表中查找元素");
puts("d) 遍历打印当前散列表");
puts("q) 退出本程序");
puts("===============================");
printf("请您输入选择: ");
while (ch = get_first(), strchr("abcdq", ch) == NULL)
{
printf("您的选择无效!请重新输入:");
}
return ch;
}
void choice(int ch, hashtable *ht)
{
elemtype val;
pnode pos = NULL;
switch (ch)
{
case 'a':
{
val = input();
insert(val, ht);
break;
}
case 'b':
{
val = input();
cancel(val, ht);
break;
}
case 'c':
{
val = input();
pos = find(val, ht);
if (pos != NULL)
{
printf("散列表中存在元素%d\n", val);
}
else
{
printf("散列表中不存在元素%d\n", val);
}
break;
}
case 'd':
{
printf("散列表如下:\n");
traverse(ht);
break;
}
}
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
return;
}
//hashtable.h
#ifndef HASHTABLE_H_
#define HASHTABLE_H_
#define TABLESIZE 11 //散列表的长度;
typedef int elemtype;
typedef unsigned int index;
typedef struct node
{
elemtype data;
struct node *next;
} list;
typedef struct node *pnode;
typedef struct
{
list *table;
int tablesize;
} hashtable; //散列表(使用链表实现);
//1) 散列函数(除留余数法);
index hash(elemtype key, int size);
/*----------------------------------------------------------------------*/
//2) 初始化大小为size的散列表;
hashtable *initialize_table(int size);
/*----------------------------------------------------------------------*/
//3) 查找散列表中是否存在元素key;
pnode find(elemtype key, hashtable *ht);
/*----------------------------------------------------------------------*/
//4) 为散列表添加元素key;
void insert(elemtype key, hashtable *ht);
/*----------------------------------------------------------------------*/
//5) 从散列表中删除元素key;
void cancel(elemtype key, hashtable *ht);
/*----------------------------------------------------------------------*/
//6) 释放散列表的存储空间;
void destroy_table(hashtable *ht);
/*----------------------------------------------------------------------*/
//7) 遍历散列表;
void traverse(hashtable *ht);
/*----------------------------------------------------------------------*/
#endif
//hashtable.c
#include <stdio.h>
#include <stdlib.h>
#include "hashtable.h"
index hash(elemtype key, int size)
{
return key % size;
}
hashtable *initialize_table(int size)
{
int i;
hashtable *new_table = NULL;
if ((new_table = (hashtable *)malloc(sizeof(hashtable))) != NULL) //分配一个散列表空间;
{
new_table->tablesize = size;
if ((new_table->table = (list *)malloc(sizeof(list) * size)) != NULL) //为散列表中的链表分配空间;
{
for (i = 0; i < size; i++)
{
new_table->table[i].next = NULL;
}
}
else
{
free(new_table);
fprintf(stderr, "动态内存分配失败!自动退出本程序!\n");
exit(EXIT_FAILURE);
}
}
else
{
fprintf(stderr, "动态内存分配失败!自动退出本程序!\n");
exit(EXIT_FAILURE);
}
return new_table;
}
pnode find(elemtype key, hashtable *ht)
{
pnode pos = NULL;
list *templist = &ht->table[hash(key, ht->tablesize)]; //查找元素key所在的位置链表;
pos = templist->next;
while (pos != NULL && pos->data != key)
{
pos = pos->next;
}
return pos;
}
void insert(elemtype key, hashtable *ht)
{
pnode pos = NULL;
pnode new_node = NULL;
list *templist = NULL;
pos = find(key, ht);
if (NULL == pos)
{
if ((new_node = (pnode)malloc(sizeof(list))) != NULL)
{
templist = &ht->table[hash(key, ht->tablesize)];
new_node->data = key;
new_node->next = templist->next;
templist->next = new_node;
printf("为散列表添加元素%d成功!\n", key);
}
else
{
fprintf(stderr, "动态内存分配失败!自动退出本程序!\n");
exit(EXIT_FAILURE);
}
}
else
{
printf("散列表中存在元素%d, 无法重复添加!\n", key);
}
return;
}
static pnode find_prior(elemtype key, hashtable *ht)
{
pnode pos = NULL;
pnode temp = NULL;
list *templist = &ht->table[hash(key, ht->tablesize)]; //查找元素key所在的位置链表;
temp = templist;
pos = templist->next;
while (pos != NULL && pos->data != key)
{
temp = pos;
pos = pos->next;
}
return temp; //返回待删除结点的前驱结点地址;
}
void cancel(elemtype key, hashtable *ht)
{
pnode pos = NULL;
pnode temp = NULL;
pos = find_prior(key, ht); //带删除元素的前驱结点位置;
temp = pos->next; //待删除元素的位置;
if (temp != NULL)
{
pos->next = temp->next;
free(temp);
printf("成功删除散列表中元素%d\n", key);
}
else
{
printf("散列表中不存在元素%d, 无法删除!\n", key);
}
return;
}
void destroy_table(hashtable *ht)
{
int i;
pnode pos = NULL;
list *templist = NULL;
for (i = 0; i < ht->tablesize; i++) //释放散列表中各个链表的空间;
{
templist = ht->table[i].next;
while (templist != NULL)
{
pos = templist;
templist = templist->next;
free(pos);
}
}
free(ht); //释放散列表空间;
return;
}
void traverse(hashtable *ht)
{
int i;
list *templist = NULL;
for (i = 0; i < ht->tablesize; i++)
{
printf("%2d: ", i);
templist = ht->table[i].next;
while (templist != NULL)
{
printf("%d", templist->data);
if (templist->next != NULL) //控制打印格式;
{
printf(" -> ");
}
templist = templist->next;
}
putchar('\n');
}
return;
}
// ------------------------------------------------ ----------------------------
// ---------------------------- 25 de enero de 2021 -------------- - ---------------