转自:http://blog.csdn.net/jdh99/article/details/8490704
哈希表算法实现
本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.
环境:
主机:WINXP
开发环境:MINGW
说明:
本程序建立的哈希表示意图:
哈希函数为对哈希表长取余
源代码:
- /*********************************************************************
- * 哈希表算法实现
- * (c)copyright 2013,jdh
- * All Right Reserved
- *文件名:main.c
- *程序员:jdh
- **********************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- /*********************************************************************
- * 宏定义
- **********************************************************************/
- /*********************************************************************
- * 数据类型重定义
- **********************************************************************/
- #define uint8_t unsigned char
- #define uint16_t unsigned short
- #define uint32_t unsigned long
- /*********************************************************************
- * 哈希表长度
- **********************************************************************/
- #define HASH_TABLE_LEN 100
- /*********************************************************************
- * 数据结构
- **********************************************************************/
- //链表节点
- typedef struct _Link_Node
- {
- uint16_t id;
- uint16_t data;
- struct _Link_Node *next;
- }Link_Node,*Link_Node_Ptr;
- //哈希表头
- typedef struct _Hash_Header
- {
- struct _Link_Node *next;
- }Hash_Header,*Hash_Header_Ptr;
- /*********************************************************************
- * 全局变量
- **********************************************************************/
- //哈希表
- Hash_Header_Ptr Hash_Table[HASH_TABLE_LEN];
- /*********************************************************************
- * 函数
- **********************************************************************/
- /*********************************************************************
- * 哈希表函数
- *说明:
- *1.用哈希函数生成id对应的哈希表中的位置
- 输入:id
- 返回:位置
- **********************************************************************/
- uint8_t hash_func(uint16_t id)
- {
- uint8_t pos = 0;
- pos = id % HASH_TABLE_LEN;
- return pos;
- }
- /*********************************************************************
- * 初始化节点
- *返回:结点指针
- **********************************************************************/
- Link_Node_Ptr init_link_node(void)
- {
- Link_Node_Ptr node;
- //申请节点
- node = (Link_Node_Ptr) malloc(sizeof(Link_Node));
- //初始化长度为0
- node->next = NULL;
- return node;
- }
- /*********************************************************************
- * 初始化哈希表头结点
- *返回哈希表头结点指针
- **********************************************************************/
- Hash_Header_Ptr init_hash_header_node(void)
- {
- Hash_Header_Ptr node;
- //申请节点
- node = (Hash_Header_Ptr) malloc(sizeof(Hash_Header));
- //初始化长度为0
- node->next = NULL;
- return node;
- }
- /*********************************************************************
- * 哈希表初始化
- *说明:
- *1.初始化哈希表Hash_Table
- *2.哈希表长度最大不能超过256
- **********************************************************************/
- void init_hash_table(void)
- {
- uint8_t i = 0;
- for (i = 0;i < HASH_TABLE_LEN;i++)
- {
- Hash_Table[i] = init_hash_header_node();
- Hash_Table[i]->next = NULL;
- }
- }
- /*********************************************************************
- * 在哈希表增加节点
- *说明:
- *1.在哈希表的某个链表末增加数据
- 输入:new_node:新节点
- **********************************************************************/
- void append_link_node(Link_Node_Ptr new_node)
- {
- Link_Node_Ptr node;
- uint8_t pos = 0;
- //新节点下一个指向为空
- new_node->next = NULL;
- //用哈希函数获得位置
- pos = hash_func(new_node->id);
- //判断是否为空链表
- if (Hash_Table[pos]->next == NULL)
- {
- //空链表
- Hash_Table[pos]->next = new_node;
- }
- else
- {
- //不是空链表
- //获取根节点
- node = Hash_Table[pos]->next;
- //遍历
- while (node->next != NULL)
- {
- node = node->next;
- }
- //插入
- node->next = new_node;
- }
- }
- /*********************************************************************
- * 在哈希表查询节点
- *说明:
- *1.知道在哈希表某处的单链表中,并开始遍历.
- *2.返回的是查询节点的前一个节点指针.这么做是为了做删除操作.
- 输入:pos:哈希表数组位置,从0开始计数
- id:所需要查询节点的id
- root:如果是根节点,则*root = 1,否则为0
- 返回:所需查询的节点的前一个节点指针,如果是根节点则返回根节点,失败返回0
- **********************************************************************/
- Link_Node_Ptr search_link_node(uint16_t id,uint8_t *root)
- {
- Link_Node_Ptr node;
- uint8_t pos = 0;
- //用哈希函数获得位置
- pos = hash_func(id);
- //获取根节点
- node = Hash_Table[pos]->next;
- //判断单链表是否存在
- if (node == NULL)
- {
- return 0;
- }
- //判断是否是根节点
- if (node->id == id)
- {
- //是根节点
- *root = 1;
- return node;
- }
- else
- {
- //不是根节点
- *root = 0;
- //遍历
- while (node->next != NULL)
- {
- if (node->next->id == id)
- {
- return node;
- }
- else
- {
- node = node->next;
- }
- }
- return 0;
- }
- }
- /*********************************************************************
- * 在哈希表删除节点
- *说明:
- *1.删除的不是当前节点,而是当前节点后的一个节点
- 输入:node:删除此节点后面的一个节点
- new_node:新节点
- **********************************************************************/
- void delete_link_node(Link_Node_Ptr node)
- {
- Link_Node_Ptr delete_node;
- //重定向需要删除的前一个节点
- delete_node = node->next;
- node->next = delete_node->next;
- //删除节点
- free(delete_node);
- delete_node = NULL;
- }
- /*********************************************************************
- * 在哈希表删除根节点
- 输入:node:根节点
- **********************************************************************/
- void delete_link_root_node(Link_Node_Ptr node)
- {
- uint8_t pos = 0;
- //用哈希函数获得位置
- pos = hash_func(node->id);
- //哈希表头清空
- if (node != NULL)
- {
- Hash_Table[pos]->next = node->next;
- //删除节点
- free(node);
- node = NULL;
- }
- }
- /*********************************************************************
- * 获得哈希表中所有节点数
- 输入:node:根节点
- **********************************************************************/
- uint16_t get_node_num(void)
- {
- Link_Node_Ptr node;
- uint16_t i = 0;
- uint16_t num = 0;
- //遍历
- for (i = 0;i < HASH_TABLE_LEN;i++)
- {
- //获取根节点
- node = Hash_Table[i]->next;
- //遍历
- while (node != NULL)
- {
- num++;
- node = node->next;
- }
- }
- return num;
- }
- /*********************************************************************
- * 从哈希表中获得对应序号的节点
- *参数:index:序号.从1开始,最大值为节点总数值
- * root:如果是根节点,则*root = 1,否则为0
- 返回:所需查询的节点的前一个节点指针,如果是根节点则返回根节点,失败返回0
- **********************************************************************/
- Link_Node_Ptr get_node_from_index(uint16_t index,uint8_t *root)
- {
- Link_Node_Ptr node;
- uint16_t i = 0;
- uint16_t num = 0;
- //遍历
- for (i = 0;i < HASH_TABLE_LEN;i++)
- {
- //获取根节点
- node = Hash_Table[i]->next;
- //判断单链表是否存在
- if (node == NULL)
- {
- continue;
- }
- //根节点
- num++;
- if (num == index)
- {
- //是根节点
- *root = 1;
- return node;
- }
- //遍历
- while (node->next != NULL)
- {
- num++;
- if (num == index)
- {
- //不是根节点
- *root = 0;
- return node;
- }
- node = node->next;
- }
- }
- return 0;
- }
- /*********************************************************************
- * 删除hash表中所有节点
- **********************************************************************/
- void drop_hash()
- {
- Link_Node_Ptr node;
- uint16_t i = 0;
- Link_Node_Ptr node_next;
- //遍历
- for (i = 0;i < HASH_TABLE_LEN;i++)
- {
- //获取根节点
- node = Hash_Table[i]->next;
- while (1)
- {
- //判断单链表是否存在
- if (node == NULL)
- {
- //不存在
- Hash_Table[i]->next = NULL;
- break;
- }
- //根节点下一个节点
- node_next = node->next;
- //删除根节点
- free(node);
- //重指定根节点
- node = node_next;
- }
- }
- }
- /*********************************************************************
- * 输出所有节点
- **********************************************************************/
- void printf_hash()
- {
- Link_Node_Ptr node;
- uint8_t root = 0;
- uint8_t i = 0;
- uint8_t num = 0;
- printf("-------------打印hash表-------------\n");
- num = get_node_num();
- for (i = 1;i <= num;i++)
- {
- node = get_node_from_index(i,&root);
- if (node != 0)
- {
- if (root)
- {
- printf("根节点:节点号%d,id为%d\n",i,node->id);
- }
- else
- {
- printf("普通节点:节点号%d,id为%d\n",i,node->next->id);
- }
- }
- }
- }
- /*********************************************************************
- * 主函数
- *说明:实现对哈希表的新建,建立节点,查询及增加,删除节点的操作
- **********************************************************************/
- int main()
- {
- Link_Node_Ptr node;
- uint8_t temp = 0;
- uint8_t root = 0;
- uint8_t i = 0;
- init_hash_table();
- //插入数据id = 1,data = 2;
- node = init_link_node();
- node->id = 1;
- node->data = 2;
- append_link_node(node);
- //查询节点数
- printf("1节点数为%d\n",get_node_num());
- node = init_link_node();
- node->id = 100;
- node->data = 101;
- append_link_node(node);
- node = init_link_node();
- node->id = 1002;
- node->data = 1001;
- append_link_node(node);
- node = init_link_node();
- node->id = 10000;
- node->data = 10001;
- append_link_node(node);
- node = init_link_node();
- node->id = 1000;
- node->data = 10001;
- append_link_node(node);
- node = init_link_node();
- node->id = 2;
- node->data = 10001;
- append_link_node(node);
- //查询节点数
- printf("2节点数为%d\n",get_node_num());
- //查询id = 1000;
- node = search_link_node(100,&temp);
- if (node != 0)
- {
- if (temp == 0)
- {
- printf("删除普通节点:所需查询id的值为%d,数据为%d\n",node->next->id,node->next->data);
- //删除
- delete_link_node(node);
- }
- else
- {
- //根节点
- printf("删除根节点所需查询id的值为%d,数据为%d\n",node->id,node->data);
- //删除
- delete_link_root_node(node);
- }
- }
- else
- {
- printf("查询失败\n");
- }
- //查询id = 1000;
- node = search_link_node(1001,&temp);
- if (node != 0)
- {
- if (temp == 0)
- {
- printf("所需查询id的值为%d\n",node->next->data);
- }
- else
- {
- //根节点
- printf("所需查询id的值为%d\n",node->data);
- }
- }
- else
- {
- printf("查询失败\n");
- }
- //查询节点数
- printf("节点数为%d\n",get_node_num());
- printf_hash();
- getchar();
- return 0;
- }