hash表-链表法
furrain 6/19/2022 algorithm
# Hash表
当存储了大量的数据时,如果进行查找,可能耗时会很久。这时,有个叫hash表的方法。
哈希表最大的优点,就是把数据的存储和查找消耗的时间大大降低,几乎可以看成是常数时间;而代价仅仅是消耗比较多的内存。 然而在当前可利用内存越来越多的情况下,用空间换时间的做法是值得的。 另外,编码比较容易也是它的特点之一。 其基本原理是:使用一个下标范围比较大的数组来存储元素
各种各样的散列hash方法见 https://blog.csdn.net/weixin_43142797/article/details/99947549
这里说一下链表实现。
#pragma once
#include <iostream>
using namespace std;
class HashTable
{
public:
HashTable() {};
~HashTable() {
delete[]mRoot;
};
void CreateHashTable(int num);
struct Node {
Node* mNextNode = nullptr;
int mValue = -1;
~Node()
{
cout << "head : " << mValue << endl;
if (mNextNode == nullptr) {
return;
}
delete mNextNode;
}
};
// 输出hash表的数据
void out()
{
for (int i = 0; i < mMaxSize; ++i) {
Node* tmp = mRoot[i].mNextNode;
if (tmp == nullptr) {
continue;
}
cout << "head : " << mRoot[i].mValue << endl;
while (tmp) {
cout << tmp->mValue << " ";
tmp = tmp->mNextNode;
}
cout << endl;
}
}
void Insert(int num);
bool Contains(int num);
private:
bool IsPrimer(int num);
int GetNextPrimer(int num);
int HashIndex(int num);
Node *mRoot = nullptr;
int mMaxSize = 0;
};
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
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
#include "HashTable.h"
#include <cmath>
/*
* brief 创建hash表
*/
void HashTable::CreateHashTable(int num)
{
int size = GetNextPrimer(num);
mMaxSize = size;
if (mRoot == nullptr) {
mRoot = new Node[size]();
for (int i = 0; i < size; ++i) {
mRoot[i].mValue = i;
}
}
}
/*
* brief 添加数据
*/
void HashTable::Insert(int num)
{
int index = HashIndex(num);
Node *tmp = mRoot[index].mNextNode;
Node* data = new Node;
data->mValue = num;
mRoot[index].mNextNode = data;
data->mNextNode = tmp;
}
/*
* brief 判断是否存在
*/
bool HashTable::Contains(int num)
{
int index = HashIndex(num);
// 这里一定要记得引用,如果不加引用,这里会变成函数内变量,会在函数结束时,析构掉。后边再用到的时候,就崩溃了.
Node &node = mRoot[index];
Node* tmp = node.mNextNode;
while (tmp) {
if (num == tmp->mValue) {
return true;
}
tmp = tmp->mNextNode;
}
return false;
}
/*
* brief 判断素数
*/
bool HashTable::IsPrimer(int num)
{
// 6x - 1 or 6x + 1
if (num == 4 || num == 1) {
return false;
}
for (int i = 5; i < std::sqrt(num); i = i + 6) {
if (num % i == 0 || (num + 2) % i == 0) {
return false;
}
}
return true;
}
/*
* brief 取得大于num的最小素数
*/
int HashTable::GetNextPrimer(int num)
{
int tmp = num % 2 == 0 ? num + 1 : num;
while (!IsPrimer(tmp)) {
tmp += 2;
}
return tmp;
}
/*
* brief 取得num在链表中的下标
*/
int HashTable::HashIndex(int num)
{
return num % mMaxSize;
}
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
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
#include "HashTable.h"
int main(int argc, char **argv)
{
HashTable hash;
int nums[10] = {11, 54, 65, 85, 75, 63, 23, 28, 29, 99};
hash.CreateHashTable(10);
for (int i = 0; i < 10; ++i) {
hash.Insert(nums[i]);
}
hash.out();
cout << hash.Contains(88) << endl;
cout << hash.Contains(99) << endl;
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15