9.6.2 哈希查找之开放定址法解决哈希碰撞

转载 2016年06月01日 22:43:29

http://blog.csdn.net/johnnyhu90/article/details/10822497

开放定址法:

(1) 线性探测法:逐个探测每个单元(必要时绕回)以查找出一个空单元。典型的冲突函数

    F(i)= i;

缺点: 容易产生一次聚集(primary clustering);

(2) 平方探测法:典型的冲突函数是:F(i) = i2,消除线性探测一次聚集的冲突解决办法。

缺点:容易产生二次聚集(secondary clustering);

定理:使用平方探测,且表的大小为素数,那么当表至少一半空的时候,总能够插入一个新元

具体详细介绍见资源:http://download.csdn.net/detail/johnnyhu90/6191597     一书的117页介绍

下面代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/***********************************************************/
// 程序名称:HashSearch_3.cpp
// 程序目的:哈希表之---分离链接散列法
// 程序来源:数据结构与算法分析(C语言描述) P-120
// 日期:2013-9-1 12:50:33 JohnnyHu修改
/***********************************************************/

#include <stdio.h>
#include <stdlib.h>

#define Error( str )        FatalError( str )
#define FatalError( str )   fprintf( stderr, "%s\n", str ), exit( 1 )

#define MinTableSize 5
#define NUMITEMS 5

typedef int ElementType;
typedef unsigned int Index;
typedef Index Position;
struct hashTbl;
typedef struct hashTbl* HashTable;

Index Hash(ElementType key, int tableSize);
HashTable InitializeTable(int tableSize);
Position Find(ElementType key, HashTable h);
void Insert(ElementType key, HashTable h);
ElementType Retrieve(Position p, HashTable h);
void DestroyTable(HashTable h);
HashTable Rehash(HashTable h);
void PrintfTable(HashTable h);

enum kindOfEntry {legitmate, empty, deleted}; // 合法的、空、删除的

struct hashEntry
{
    ElementType element;
    enum kindOfEntry info;
};
typedef struct hashEntry Cell;

struct hashTbl
{
    int tableSize;
    Cell* theCells;
};

int main(void)
{
    HashTable hashTable;
    int currentSize;
    hashTable = InitializeTable(currentSize = 7);   // 当前哈希表的大小为13

    int insertedNum = 0;        // 标识插入表中元素个数
    for (int i = 0, j = 1; i < NUMITEMS; i++, j += 2)
    {
        if( i > currentSize / 2 )
        {
            hashTable = Rehash( hashTable );  // 再散列
            printf( "插入元素数超过: %d, Rehashing(再散列)...\n" , i);
            currentSize *= 2;
        }

        Insert(j, hashTable);
        insertedNum++;
    }

    printf("输出哈希表中数据: \n");
    PrintfTable(hashTable);

    int keyValue;
    printf("输入要插入的(int)值(-1则退出输入操作):");
    scanf("%d", &keyValue);
    while (-1 != keyValue)
    {
        if( insertedNum > currentSize / 2 )
        {
            hashTable = Rehash( hashTable );  // 再散列
            printf( "插入元素数超过: %d, Rehashing(再散列)...\n" , insertedNum);
            currentSize *= 2;
        }
        Insert(keyValue, hashTable);
        insertedNum++;

        printf("输入要插入的(int)值(-1则退出输入操作):");
        scanf("%d", &keyValue);
    }


    printf("执行插入后的哈希表数据:\n");
    PrintfTable(hashTable);

    // 检测各个值
    Position pos;
    for (int i=0, j=1; i < NUMITEMS; i++, j += 2)
    {
        if ( Retrieve((pos = Find(j, hashTable)), hashTable)  != j )
            printf("在%d处出错!\n", j);
    }
    printf("程序执行完毕!\n");

    DestroyTable(hashTable); // 释放内存空间

    return 0;
}

/************************************************************************/
// 返回下一个素数(与n仅接着的素数)
/************************************************************************/

static int NextPrime(int n)
{
    int i;

    if( n % 2 == 0 )
        n++;
    for( ; ; n += 2 )
    {
        for( i = 3; i * i <= n; i += 2 )
        {
            if( n % i == 0 )
                goto ContOuter;  /* Sorry about this! */
        }
        return n;
        ContOuter: ;
    }
}

/************************************************************************/
// 哈希函数
/************************************************************************/

Index Hash(ElementType key, int tableSize)
{
    return key % tableSize;
}

/************************************************************************/
// 初始化哈希表
/************************************************************************/

HashTable InitializeTable(int tableSize)
{   
    if (tableSize < MinTableSize)
    {
        Error("要创建的表太小!");
        return NULL;
    }

    HashTable h;
    h = (HashTable)malloc(sizeof(struct hashTbl));
    if (NULL == h)
        FatalError("内存分配失败!");

    h->tableSize = NextPrime(tableSize);  // 哈希表大小是素数

    h->theCells = (Cell*)malloc(sizeof(Cell) * h->tableSize);
    if (NULL == h->theCells)
        FatalError("给数组内存分配失败!");

    for (int i = 0; i < h->tableSize; i++)
        h->theCells[i].info = empty;

    return h;
}

/************************************************************************/
// 哈希表查找
/************************************************************************/

Position Find(ElementType key, HashTable h)
{
    Position correntPos;
    int collisionNum;

    collisionNum = 0;
    correntPos = Hash(key, h->tableSize);
    while (h->theCells[correntPos].info != empty &&
            h->theCells[correntPos].element != key)
    { // 这里进行平方探测
        correntPos += 2 * ++collisionNum  - 1;
        if (correntPos >= h->tableSize)
            correntPos -= h->tableSize;
    }

    return correntPos;
}

/************************************************************************/
// 哈希表插入
/************************************************************************/

void Insert(ElementType key, HashTable h)
{
    Position pos;

    pos = Find(key, h);
    if (h->theCells[pos].info != legitmate)
    {
        h->theCells[pos].info = legitmate;
        h->theCells[pos].element = key;
    }
}

/************************************************************************/
// 开放定址列表再散列
/************************************************************************/

HashTable Rehash(HashTable h)
{
    int oldSize;
    Cell* oldCells;

    oldCells = h->theCells;
    oldSize = h->tableSize;

    // 获得新的空表
    h = InitializeTable(2 * oldSize);

    for (int i = 0; i < oldSize; i++)
    {
        if (oldCells[i].info == legitmate)
            Insert(oldCells[i].element, h);
    }

    free(oldCells);

    return h;
}
/************************************************************************/
// 获取键值
/************************************************************************/

ElementType Retrieve(Position p, HashTable h)
{
    return h->theCells[p].element;
}

/************************************************************************/
// 哈希表销毁
/************************************************************************/

void DestroyTable(HashTable h)
{
    free(h->theCells);
    free(h);

    return;
}

/************************************************************************/
// Fuction:打印哈希表
// target:  测试哈希表中数据
// Author:  Johnny Hu
// Date:    2013-9-1 6:36:38
/************************************************************************/

void PrintfTable(HashTable h)
{
    Cell* printCells;
    printCells = h->theCells;
    for (int i=0; i < h->tableSize; i++)
    {
        if (printCells[i].info == legitmate)
            printf("hashtable[%d]: [%d]\n", i, printCells[i].element);
        else if (printCells[i].info == empty)
            printf("hashtable[%d]: [ ]\n", i);
            
    }
}
输出结果:




相关文章推荐

Hash碰撞与拒绝服务攻击

http://www.cnblogs.com/xuanhun/archive/2012/01/01/2309571.html 1.Hash与Hash碰撞        Ha...

哈希表碰撞攻击的基本原理

原文地址:http://blog.jobbole.com/11516/ 来源:张洋 最近哈希表碰撞攻击(Hashtable collisions as DOS attack)的话题不断被提起,各种...

9.6.2 哈希查找之开放定址法解决哈希碰撞

开发定址法: (1) 线性探测法:逐个探测每个单元(必要时绕回)以查找出一个空单元。典型的冲突函数     F(i) = i; 缺点: 容易产生一次聚集(primary clustering); (2...

java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区

一)哈希表简介 非哈希表的特点:关键字在表中的位置和它之间不存在一个确定的关系,查找的过程为给定值一次和各个关键字进行比较,查找的效率取决于和给定值进行比较的次数。     哈希表的特点:关键字...

哈希(散列)表之开放定址法的C++类模板实现

一 简介 散列表(Hash table哈希表),根据关键码值(Key value)而直接进行访问的数据结构。 通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。 这个映射函数叫做散列函...

哈希查找法

24-哈希碰撞攻击是什么?

24-哈希碰撞攻击是什么?最近哈希表碰撞攻击(Hashtable collisions as DOS attack)的话题不断被提起,各种语言纷纷中招。本文结合PHP内核源码,聊一聊这种攻击的原理及实...

深入PHP内核(三)——内核利器哈希表与哈希碰撞攻击

深入PHP内核(三)——内核利器哈希表与哈希碰撞攻击 在PHP的Zend Engine(下面简称ZE)中,有一个非常重要的数据结构——哈希表(HashTable)。哈希表在ZE中有非常广泛的应用,P...

哈希碰撞攻击

哈希表碰撞攻击的基本原理 哈希表是一种查找效率极高的数据结构,很多语言都在内部实现了哈希表。PHP中的哈希表是一种极为重要的数据结构,不但用于表示Array数据类型,还在Zend虚拟机内部用于存...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)