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);
            
    }
}
输出结果:




散列表之开放定址法

散列表之开放定址法 散列表的基本操作 插入操作_INSERT 查找操作_SEARCH 删除操作_DELETE 散列表的探查方法probe methods 散列表探查的定义 线性探查 二次探查 双重散列...
  • ii1245712564
  • ii1245712564
  • 2015年07月12日 00:13
  • 2697

开放定址法(线性探测),拉链法 -Hash算法

总结:哈希别名为:Hash 或者 散列表; 开放定址法是为了解决hash值碰撞后的处理;散列表(哈希)是算法在时间和空间上作出权衡的经典例子。 如果没有内存限制,我们可以直接将键作为(可能是一个超...
  • ccy365263452
  • ccy365263452
  • 2016年12月30日 09:11
  • 1500

hash之开放定址法解决冲突

 /*hash表之开放定址法处理冲突:*/ 方法一: /* 根据提示输入学生信息,然后输入查找学生的学号,如果有的话,输出学生姓名和位置,如果没有的话,提示没有该学生的信息。 */ ...
  • legend050709
  • legend050709
  • 2014年08月16日 17:06
  • 1025

(第13讲)哈希表的开放地址法中的线性探测

哈希表:也叫散列表(Hash table,),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散...
  • weiyastory
  • weiyastory
  • 2016年07月13日 16:27
  • 836

算法学习 - HashTable开放地址法解决哈希冲突

开放地址法解决哈希冲突 线性开放地址法 线性开放地址法就是在hash之后,当发现在位置上已经存在了一个变量之后,放到它下一个位置,假如下一个位置也冲突,则继续向下,依次类推,直到找到没有变量的位置...
  • chenfs1992
  • chenfs1992
  • 2014年08月10日 01:08
  • 1712

散列表的C语言实现-开放定址法

头文件: #ifndef __HASHTABLE_H #define __HASHTABLE_H /*********************(平方)开放定址散列法***************...
  • u012000209
  • u012000209
  • 2015年08月09日 11:25
  • 733

C语言开放地址法哈希表构建

  • 2012年08月04日 22:38
  • 2.62MB
  • 下载

C语言实现的数据结构之------哈希表

1 哈希表原理这里不讲高深理论,只说直观感受。哈希表的目的就是为了根据数据的部分内容(关键字),直接计算出存放完整数据的内存地址。试想一下,如果从链表中根据关键字查找一个元素,那么就需要遍历才能得到这...
  • smstong
  • smstong
  • 2016年04月13日 19:27
  • 18345

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

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

哈希表查找 — 开放定址法

散列表(也叫哈希表),是根据关键字值而直接进行访问的数据结构。通过把关键字值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。散列函数的构造方法: ...
  • learn_sunzhuli
  • learn_sunzhuli
  • 2015年07月26日 17:07
  • 998
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:9.6.2 哈希查找之开放定址法解决哈希碰撞
举报原因:
原因补充:

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