关闭

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

127人阅读 评论(0) 收藏 举报
分类:

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




0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:803982次
    • 积分:12206
    • 等级:
    • 排名:第1174名
    • 原创:345篇
    • 转载:1022篇
    • 译文:32篇
    • 评论:55条
    最新评论