alicelmx 2020-01-29
哈希函数:在记录的关键字与记录的存储地址之间建立的一 种对应关系叫哈希函数。
哈希函数是一种映象,是从关键字空间到存储地址空间的一 种映象。可写成:addressi=H(keyi) ,其中i是表中某 个元素。
哈希表:应用哈希函数,由记录的关键字确定记录在表中的 地址,并将记录放入此地址,这样构成的表叫哈希
★哈希表的特点就是数据与其在表中的位置存在相关性,也就是有关系的,通过数据应该可以计算其位置,哈希表最大的特点是是可以快速实现查找,插入和删除。因为它独有的特点,Hash表经常用来解决大数据问题
1.哈希表的基本思想
数组的最大的特点是:寻址容易,插入和删除困难;而链表正好相反,寻址困难,而插入和删除操作容易。那么如果能够结合两者的优点。做出一种寻址,插入和删除操作同样快速的数据结构,这就是哈希表。哈希表是这样一个集查找,插入和删除操作于一身的数据结构
2.哈希表结构
3.基本操作
//创建结构体存储键值对 struct element { int key; int value; }; //创建结构体作为一级结构 struct table; //初始化哈希表存储空间,返回指向该空间的结构体指针变量 struct table *table_init(); void table_free(struct table *t); void table_clear(struct table *t); int table_isempty(struct table *t); int table_count(struct table *t); //将新的键值对存储到哈希表存储结构中 void table_put(struct table *t, int key, int value); // void table_put(struct table *t, struct element e); //根据键值将键值对从哈希表存储结构中移除 struct element table_remove(struct table *t, int key); /* 如果找到了返回key的元素,如果没找到返回{-1,-1}*/ struct element table_get(struct table *t, int key);
4.存储结构
结构①
核心思想:使用结构体数组存储键值对作为哈希表的存储结构核心
结构②
核心思想:将链表连接到数组中,数组变量作为各链表的索引达到方便操作数据的目的
5.代码实现
table.h
#ifndef __TABLE_H__ #define __TABLE_H__ //定义结构体存储键值对 struct element { int key; int value; }; struct table; struct table *table_init(); void table_free(struct table *t); void table_clear(struct table *t); int table_isempty(struct table *t); int table_count(struct table *t); void table_put(struct table *t, int key, int value); struct element table_remove(struct table *t, int key); struct element table_get(struct table *t, int key); #endif
main.c
//将数据元素按照键值关系存储到哈希表存储结构中 #include <stdio.h> #include <stdlib.h> #include "table.h" int main(int argc, char *argv[]) { //定义结构体指针变量t指向table结构体类型的数据 struct table *t = NULL; int i; //定义element结构体类型变量e struct element e; //t指向已开辟的内存空间 t = table_init(); table_put(t,0,55); table_put(t, 1, 100); table_put(t, 2, 200); table_put(t, 3, 300); table_put(t, 5, 500); //键相同会产生"冲突",键不变,值覆盖 table_put(t, 3, 333); //循环遍历,将键值取出 for (i=0; i<10; i++) { e = table_get(t, i); printf("the element is <%d, %d>\n", e.key, e.value); } table_free(t); system("PAUSE"); return 0; }
table.c
结构⑴
#include "table.h" #include <stdlib.h> #include <assert.h> #include <string.h> //定义数组的初始长度 #define TABLE_INIT_SIZE 1 //定义数组每次扩容增加的长度 #define TABLE_INCR_SIZE 1 //定义table结构体类型作为一级结构体,指针变量elements指向在.h文件中定义的element结构体类型数据元素 //count记录结构体数组中数据元素的个数,size记录结构体数组的长度 struct table { struct element *elements; int count; int size; }; //创建以结构体数组为核心的哈希表存储结构 struct table *table_init() { struct table *t = NULL; t = (struct table *)malloc(sizeof(struct table)); if (t == NULL) return NULL; assert(t != NULL); t->elements = NULL; t->size = 0; t->count = 0; t->elements = (struct element *)malloc(sizeof(struct element) * TABLE_INIT_SIZE); if (t->elements == NULL) { free(t); return NULL; } assert(t->elements != NULL); memset(t->elements, 0, sizeof(struct element) * TABLE_INIT_SIZE); t->size = TABLE_INIT_SIZE; return t; } //通过table_free()释放内存空间 void table_free(struct table *t) { assert(t != NULL); assert(t->elements != NULL); free(t->elements); free(t); return; } //清空哈希表存储结构中的数据元素 void table_clear(struct table *t) { assert(t != NULL); assert(t->elements != NULL); t->count = 0; return; } //查看哈希表存储结构中是否为空 int table_isempty(struct table *t) { assert(t != NULL); assert(t->elements != NULL); return (t->count == 0); } //计算哈希表存储结构中数据元素的个数 int table_count(struct table *t) { assert(t != NULL); assert(t->elements != NULL); return t->count; } //将键值对push到哈希表存储结构中 void table_put(struct table *t, int key, int value) { //如果已存储的数据元素等于已定义的数组的长度,进行扩容操作 if (t->count == t->size) { t->elements = (struct element *)realloc(t->elements, sizeof(struct element) * (t->size + TABLE_INCR_SIZE)); if (t->elements == NULL) { perror("struct table_put realloc error"); exit(1); } t->size += TABLE_INCR_SIZE; } struct element e = {key, value}; int i=0; //如果产生"冲突",键不变,值覆盖 for (; i<t->count; i++) { if (t->elements[i].key == e.key) { t->elements[i].value = e.value; return; } } t->elements[i] = e; // t->count t->count++; return; } // void table_put(struct table *t, struct element e); //将制定键的键值对移除 struct element table_remove(struct table *t, int key) { struct element e = {-1, -1}; int i=0; //定义pos标识键相同与制定键相同的键值对所在结构体中的位置 int pos = -1; for (; i<t->count; i++) { e=t->elements[key]; if (t->elements[i].key == key) { pos = i; break; } } //后面的数据元素往前移位 if (pos != -1) { e = t->elements[pos]; for (; pos < t->count-1; pos++) { t->elements[pos] = t->elements[pos+1]; } t->count--; } return e; } struct element table_get(struct table *t, int key) { int i; struct element e = {-1, -1}; /*未找到返回的值*/ for (i=0;i<t->count; i++) { if (t->elements[i].key == key) return t->elements[i]; } return e; }
结构⑵
#include "table.h" #include <stdlib.h> #include <assert.h> #include <string.h> //定义作为索引的数组的长度 #define TABLE_SLOTS_INIT_SIZE 10 //定义table_node的结构体类型作为链表的数据节点,e为element结构体类型的数据元素(element结构体在.h文件中已定义) //next指向下一个table_node数据类型的数据 struct table_node { struct element e; struct table_node *next; }; //table结构体类型作为一级结构,数据节点地址存储在数组中,数组的首地址存放在slots指针变量中 struct table { struct table_node **slots; int count; int size; }; struct table *table_init() { struct table *t = NULL; t = (struct table *)malloc(sizeof(struct table)); if (t == NULL) return NULL; assert(t != NULL); t->slots = NULL; t->count = 0; t->size = 0; t->slots = (struct table_node **)malloc(sizeof(struct table_node *) * TABLE_SLOTS_INIT_SIZE); if (t->slots == NULL) { free(t); return NULL; } assert(t->slots != NULL); memset(t->slots, 0, sizeof(struct table_node *) * TABLE_SLOTS_INIT_SIZE); t->size = TABLE_SLOTS_INIT_SIZE; return t; } void table_free(struct table *t) { struct table_node *node = NULL; int i; for (i=0; i<t->count; i++) { while (t->slots[i] != NULL) { node = t->slots[i]; t->slots[i] = node->next; free(node); } assert(t->slots[i] == NULL); } free(t->slots); free(t); return; } void table_clear(struct table *t) { struct table_node *node = NULL; int i; assert(t != NULL); assert(t->slots != NULL); for (i = 0; i < t->count; i++) { while (t->slots[i] != NULL) { node = t->slots[i]; t->slots[i] = node->next; free(node); } assert(t->slots[i] == NULL); } t->count = 0; return; } int table_isempty(struct table *t) { assert(t != NULL); assert(t->slots != NULL); return (t->count == 0); } int table_count(struct table *t) { assert(t != NULL); assert(t->slots != NULL); return (t->count); } void table_put(struct table *t, int key, int value) { struct table_node *p = NULL; struct table_node *node = NULL; p = t->slots[key % t->size]; while (p != NULL) { if (p->e.key == key) { p->e.value = value; return; } p = p->next; } node = (struct table_node *)malloc(sizeof(struct table_node)); if (node == NULL) { perror("table_put malloc error"); exit(1); } assert(node != NULL); node->e.key = key; node->e.value = value; /* 把链上结点挂在node结点之后,注意,链上没有结点也没关系*/ node->next = t->slots[key % t->size]; t->slots[key % t->size] = node; t->count++; return; } // void table_put(struct table *t, struct element e); struct element table_remove(struct table *t, int key) { struct table_node *p = NULL; struct table_node *node = NULL; struct element e = {-1, -1}; p = t->slots[key % t->size]; if (p->e.key == key) { node = p; t->slots[key % t->size] = node->next; e = node->e; free(node); t->count--; return e; } while (p != NULL && p->next != NULL) { if (p->next->e.key == key) { node = p->next; p->next = node->next; e = node->e; t->count--; free(node); return e; } p = p->next; } return e; } /* 如果找到了返回key的元素,如果没找到返回{-1,-1}*/ struct element table_get(struct table *t, int key) { struct table_node *p = NULL; struct element e = {-1, -1}; p = t->slots[key % t->size]; while (p != NULL) { if (p->e.key == key) { e = p->e; break; } p = p->next; } return e; }
6.编译结果