您的位置:首页 > 其它

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

2016-06-01 22:43 309 查看
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);

            

    }

}
输出结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: