散列(Hash)是一种以常数复杂度实现查找功能的数据结构。它将一个关键词Key,通过某种映射(哈希函数)转化成索引值直接定位到相应位置。

实现散列有两个关键,一是哈希函数的选择,二是冲突的处理。

对于哈希函数,例程中以“Key为int型,操作为取(关于表长的)模”为例。事实上,可以直接将其换成任何一个哈希函数,不会影响实现。

对于冲突处理,有两大类处理方案,一是分离链接法,二是开放定址法。开放定址法包括线性探测法、平方探测法、双散列法等,本文给出分离链接法和平方探测法的实现。

1. 分离链接法:

// HashSep.h

#include <stdio.h>
#include <stdlib.h> struct ListNode;
typedef struct ListNode *Position;
struct HashTbl;
typedef struct HashTbl *HashTable; typedef Position List; HashTable InitializeTable(int TableSize);
void DestroyTable(HashTable H);
Position Find(ElementType Key, HashTable H);
void Insert(ElementType Key, HashTable H);

  

// HashSep.c

#include "HashSep.h"

struct ListNode
{
ElementType Key;
Position Next;
}; struct HashTbl
{
int TableSize;
List *TheLists;
}; int NextPrime(int N)
{
if (N % 2 == 0)
N++;
int i;
int NotPrime = 0;
for (;; N += 2)
{
NotPrime = 0;
for (i = 3; i * i <= N; i += 2)
if (N % i == 0)
{
NotPrime = 1;
break;
}
if (!NotPrime)
return N;
}
} int Hash(ElementType Key, int TableSize)
{
return Key * Key % 10;
} HashTable InitializeTable(int TableSize)
{
HashTable H;
int i;
if ((H = (HashTable)malloc(sizeof(struct HashTbl))) == NULL)
{
printf("Error! Out of memory! \n");
return NULL;
}
H->TableSize = NextPrime(TableSize);
H->TheLists = (Position *)malloc(H->TableSize * sizeof(Position));
for (i = 0; i < H->TableSize; i++)
{
if ((H->TheLists[i] = (List)malloc(sizeof(struct ListNode))) == NULL)
{
printf("Error! Out of memory! \n");
return NULL;
}
H->TheLists[i]->Next = NULL;
}
return H;
} void DestroyTable(HashTable H)
{
int i;
for (i = 0; i < H->TableSize; i++)
{
Position p, q;
q = H->TheLists[i];
p = q->Next;
while(p)
{
free(q);
q = p;
p = p->Next;
}
}
free(H);
} int Same(ElementType e1, ElementType e2)
{
return e1 == e2;
} Position Find(ElementType Key, HashTable H)
{
Position p;
p = H->TheLists[Hash(Key, H->TableSize)]->Next;
while(p)
{
if(Same(p->Key, Key))
break;
p = p->Next;
}
return p;
} void Insert(ElementType Key, HashTable H)
{
Position p;
List L;
if(Find(Key, H) != NULL)
return;
if((p = (Position)malloc(sizeof(struct ListNode))) == NULL)
{
printf("Error! Out of memory! \n");
return;
}
p->Key = Key;
L = H->TheLists[Hash(Key, H->TableSize)];
p->Next = L->Next;
L->Next = p;
}

  

2. 平方探测法

// HashQuad.h

#include <stdio.h>
#include <stdlib.h> typedef unsigned int Index;
typedef Index Position; struct HashTbl;
typedef struct HashTbl *HashTable; typedef struct HashEntry Cell; HashTable InitializeTable(int TableSize);
void DestroyTable(HashTable H);
Position Find(ElementType Key, HashTable H);
void Insert(ElementType Key, HashTable H);
ElementType Retrieve(Position P, HashTable H);
HashTable ReHash(HashTable H);

  

// HashQuad.c

#include "HashQuad.h"

enum KindOfEntry
{
Legitimate,
Empty,
Deleted
}; struct HashEntry
{
ElementType Element;
enum KindOfEntry Info;
}; struct HashTbl
{
int TableSize;
Cell *TheCells;
}; int NextPrime(int N)
{
if (N % 2 == 0)
N++;
int i;
int NotPrime = 0;
for (;; N += 2)
{
NotPrime = 0;
for (i = 3; i * i <= N; i += 2)
if (N % i == 0)
{
NotPrime = 1;
break;
}
if (!NotPrime)
return N;
}
} Index Hash(ElementType Key, int TableSize)
{
return Key % TableSize;
} HashTable InitializeTable(int TableSize)
{
HashTable H;
int i;
if ((H = (HashTable)malloc(sizeof(struct HashTbl))) == NULL)
{
printf("Error!\n");
return NULL;
}
H->TableSize = NextPrime(TableSize);
if ((H->TheCells = (Cell *)malloc(sizeof(Cell) * H->TableSize)) == NULL)
{
printf("Error!\n");
return NULL;
}
for (i = 0; i < H->TableSize; i++)
H->TheCells[i].Info = Empty;
return H;
} void DestroyTable(HashTable H)
{
free(H->TheCells);
free(H);
} Position Find(ElementType Key, HashTable H)
{
Index id = Hash(Key, H->TableSize);
int i = 0;
while (H->TheCells[id].Info == Legitimate && H->TheCells[id].Element != Key)
{
id += (++i << 1) - 1;
if (id >= H->TableSize)
id -= H->TableSize;
}
return id;
} void Insert(ElementType Key, HashTable H)
{
Position p = Find(Key, H);
if (H->TheCells[p].Info != Legitimate)
{
H->TheCells[p].Element = Key;
H->TheCells[p].Info = Legitimate;
}
} ElementType Retrieve(Position P, HashTable H)
{
return H->TheCells[P].Element;
} HashTable ReHash(HashTable H)
{
int i;
int OldSize;
Cell *OldCells;
OldCells = H->TheCells;
OldSize = H->TableSize;
H = InitializeTable(2 * OldSize);
for(i = 0; i < H->TableSize; i++)
if(OldCells[i].Info == Legitimate)
Insert(OldCells[i].Element, H);
free(OldCells);
return H;
}

  

《数据结构与算法分析——C语言描述》ADT实现(NO.05) : 散列(Hash)的更多相关文章

  1. 《数据结构与算法分析——C语言描述》ADT实现(NO.00) : 链表(Linked-List)

    开始学习数据结构,使用的教材是机械工业出版社的<数据结构与算法分析——C语言描述>,计划将书中的ADT用C语言实现一遍,记录于此.下面是第一个最简单的结构——链表. 链表(Linked-L ...

  2. 数据结构与算法分析——C语言描述 第三章的单链表

    数据结构与算法分析--C语言描述 第三章的单链表 很基础的东西.走一遍流程.有人说学编程最简单最笨的方法就是把书上的代码敲一遍.这个我是头文件是照抄的..c源文件自己实现. list.h typede ...

  3. 最小正子序列(序列之和最小,同时满足和值要最小)(数据结构与算法分析——C语言描述第二章习题2.12第二问)

    #include "stdio.h" #include "stdlib.h" #define random(x) (rand()%x) void creat_a ...

  4. C语言学习书籍推荐《数据结构与算法分析:C语言描述(原书第2版)》下载

    维斯 (作者), 冯舜玺 (译者) <数据结构与算法分析:C语言描述(原书第2版)>内容简介:书中详细介绍了当前流行的论题和新的变化,讨论了算法设计技巧,并在研究算法的性能.效率以及对运行 ...

  5. 《数据结构与算法分析-Java语言描述》 分享下载

    书籍信息 书名:<数据结构与算法分析-Java语言描述> 原作名:Data Structures and Algorithm Analysis in Java 作者: 韦斯 (Mark A ...

  6. 读书笔记:《数据结构与算法分析Java语言描述》

    目录 第 3 章 表.栈和队列 3.2 表 ADT 3.2.1 表的简单数组实现 3.2.2 简单链表 3.3 Java Collections API 中的表 3.3.1 Collection 接口 ...

  7. 《数据结构与算法分析——C语言描述》ADT实现(NO.03) : 二叉搜索树/二叉查找树(Binary Search Tree)

    二叉搜索树(Binary Search Tree),又名二叉查找树.二叉排序树,是一种简单的二叉树.它的特点是每一个结点的左(右)子树各结点的元素一定小于(大于)该结点的元素.将该树用于查找时,由于二 ...

  8. 《数据结构与算法分析——C语言描述》ADT实现(NO.04) : AVL树(AVL-Tree)

    上次我们已经实现了普通的二叉查找树.利用二叉查找树,可以用O(logN)高度的树状结构存储和查找数据,提高了存储和查找的效率. 然而,考虑一种极端情形:依次插入1,2,3,4,5,6,7,8,9九个元 ...

  9. 《数据结构与算法分析——C语言描述》ADT实现(NO.01) : 栈(Stack)

    这次的数据结构是一种特殊的线性表:栈(Stack) 栈的特点是后入先出(LIFO),可见的只有栈顶的一个元素. 栈在程序中的地位非常重要,其中最重要的应用就是函数的调用.每次函数调用时都会创建该函数的 ...

随机推荐

  1. 二分图带权匹配-Kuhn-Munkres算法模板 [二分图带权匹配]

    尴尬...理解不太好T T #include<cstdio> #include<cstring> #include<iostream> #include<al ...

  2. Myeclipse从外部导入项目时,jsp和html页面中所有的onclick="return xx()"位置均出现cannot return from outside function() or method()错误

  3. python定时任务模块APScheduler

    一.简单任务 定义一个函数,然后定义一个scheduler类型,添加一个job,然后执行,就可以了 5秒整倍数,就执行这个函数 # coding:utf-8 from apscheduler.sche ...

  4. Spring基础面试题(一)

    Spring是什么? Spring是一个轻量级的IoC和AOP容器框架.是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求.常见的配置方式有 ...

  5. 简单总结Class.forName("").newinstance()和new()以及classLoader.loadClass("")的区别

    文章目录 背景 三种方法简单介绍 Class.forName("").newinstance()方式 new方式 classLoader.loadClass("" ...

  6. 夏令营501-511NOIP训练16——数字转换

    传送门:QAQQAQ 题意:如果一个数x的约数和(不包括它本身,下同)比它本身小,那么x可以变成它的约数和:如果对于某个y>x且y的约数和为x,那么x也可以变成y.例如,4可以变为3,1可以变为 ...

  7. 第三方模块requests下载

    requests下载 英文网站 http://docs.python-requests.org/en/master/ 中文网站 http://docs.python-requests.org/zh_C ...

  8. JVM 内存模型及垃圾回收

    java内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 程序计数器:程序计数器是指CPU中的寄存器,它保存的是程序当前执行的指令的地址(也可以说 ...

  9. 读书笔记 | 敏捷编码&敏捷调试

    这周的个人项目让我感受到自己在编程方面的不足和缺陷,所以选择了<高效程序员的45个习惯>中的敏捷开发和敏捷调试两个章节进行阅读. 以下将对敏捷开发和敏捷调试展开详述. [敏捷开发] 注释 ...

  10. SpringBoot之集成通用Mapper

    第一种: 1.引入POM坐标,需要同时引入通用mapper和jpa <dependency> <groupId>tk.mybatis</groupId> <a ...