散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组就是散列表。散列表是算法上时间和空间做出权衡的例子,如果没有内存限制,我们可以直接将键作为数据的索引直接一次访问即可,如果没有时间限制我们直接通过之前的无序数组进行顺序查找即可。散列函数能够直接将关键字转化成索引,但是会出现相同索引的情况,这个时候我们需要处理冲突碰撞,我们会使用到拉链法和线性探测法解决碰撞问题。
拉链法
将整数散列最常用的就是除留余数法,浮点数字可以转为二进制数字然后使用除留余数法,字符串可以通过Horner的算法计算散列值,本文就简单的通过整数进行散列然后通过拉链法解决碰撞,需要用到本人之前的文章的算法-符号表的实现(顺序查找和二分查找):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@interface
HashTable :
NSObject
-(instancetype)initWithData:(
NSInteger
)linkCount;
@property
(assign,
nonatomic
)
NSInteger
count;
//键值对总数
@property
(assign,
nonatomic
)
NSInteger
linkCount;
//散列表的大小
@property
(strong,
nonatomic
)
NSMutableArray
*sequenceTableArr;
//存储顺序链表的数组
-(
NSInteger
)getHashCodeByKey:(
NSString
*)key;
-(
void
)putData:(
NSString
*)key value:(
NSString
*)value;
-(
NSString
*)getValue:(
NSString
*)key;
@end
|
实现代码:
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
|
@implementation
HashTable
-(instancetype)initWithData:(
NSInteger
)linkCount{
self
=[
super
init];
if
(
self
) {
self
.linkCount=linkCount;
SequenceTable *sequenceTable;
for
(
NSInteger
i=0; i<linkCount; i++) {
sequenceTable=[[SequenceTable alloc]init];
[
self
.sequenceTableArr addObject:sequenceTable];
}
}
return
self
;
}
-(
NSMutableArray
*)sequenceTableArr{
if
(!_sequenceTableArr) {
_sequenceTableArr=[[
NSMutableArray
alloc]initWithCapacity:1];
}
return
_sequenceTableArr;
}
-(
NSInteger
)getHashCodeByKey:(
NSString
*)key{
NSInteger
value=[key integerValue];
return
value%
self
.linkCount;
}
-(
void
)putData:(
NSString
*)key value:(
NSString
*)value{
NSInteger
index=[
self
getHashCodeByKey:key];
SequenceTable *table =
self
.sequenceTableArr[index];
[table put:key value:value];
}
-(
NSString
*)getValue:(
NSString
*)key{
NSInteger
index=[
self
getHashCodeByKey:key];
SequenceTable *table =
self
.sequenceTableArr[index];
return
[table get:key];
}
@end
|
测试代码:
1
2
3
4
5
6
7
8
9
10
11
|
HashTable *hashTable=[[HashTable alloc]initWithData:5];
[hashTable putData:@
"3"
value:@
"FlyElephant"
];
[hashTable putData:@
"5"
value:@
"原文地址:http://www.cnblogs.com/xiaofeixiang"
];
[hashTable putData:@
"2"
value:@
"博客园"
];
[hashTable putData:@
"1"
value:@
"技术交流:228407086"
];
[hashTable putData:@
"7"
value:@
"keso"
];
[hashTable putData:@
"8"
value:@
"上海"
];
[hashTable putData:@
"9"
value:@
"北京"
];
[hashTable putData:@
"10"
value:@
"深圳"
];
NSString
*temp=[hashTable getValue:@
"5"
];
NSLog
(@
"keso:%@"
,temp);
|
线性探测法
解决碰撞的另外一个方法就是用大小为M的数组存储N个键值对,其中M>N,我们可以依靠数组的空位解决冲突的问题的,如果索引已经存在我们会依次向后找一直找到一个空位为止,首尾相连,实现的的时候将key和value分为两个数组实现,类似于符号表的二分查找:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@interface
LinearHashTable :
NSObject
-(instancetype)initWithData:(
NSInteger
)capcity;
@property
(assign,
nonatomic
)
NSInteger
count;
//符号表中键值对的总数
@property
(assign,
nonatomic
)
NSInteger
capticity;
//数组的大小
@property
(strong,
nonatomic
)
NSMutableArray
*keys;
@property
(strong,
nonatomic
)
NSMutableArray
*values;
-(
NSInteger
)getHashCodeByKey:(
NSString
*)key;
-(
void
)putData:(
NSString
*)key value:(
NSString
*)value;
-(
NSString
*)getValue:(
NSString
*)key;
@end
|
实现代码:
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
|
@implementation
LinearHashTable
-(instancetype)initWithData:(
NSInteger
)capcity{
self
=[
super
init];
if
(
self
) {
self
.capticity=capcity;
for
(
NSInteger
i=0;i<capcity;i++) {
[
self
.keys addObject:[
NSNull
null]];
[
self
.values addObject:[
NSNull
null]];
}
}
return
self
;
}
-(
NSMutableArray
*)keys{
if
(!_keys) {
_keys=[[
NSMutableArray
alloc]initWithCapacity:
self
.capticity];
}
return
_keys;
}
-(
NSMutableArray
*)values{
if
(!_values) {
_values=[[
NSMutableArray
alloc]initWithCapacity:
self
.capticity];
}
return
_values;
}
-(
void
)resize:(
NSInteger
)capcity{
LinearHashTable *table=[[LinearHashTable alloc]initWithData:capcity];
for
(
NSInteger
i=0;i<
self
.capticity; i++) {
if
(
self
.keys[i]!=[
NSNull
null]) {
[table putData:
self
.keys[i] value:
self
.values[i]];
}
}
self
.keys=table.keys;
self
.values=table.values;
self
.capticity=table.capticity;
}
-(
NSInteger
)getHashCodeByKey:(
NSString
*)key{
return
[key integerValue]%
self
.capticity;
}
-(
void
)putData:(
NSString
*)key value:(
NSString
*)value{
if
(
self
.count>=
self
.capticity/2) {
[
self
resize:
self
.capticity*2];
}
NSInteger
i;
for
(i=[
self
getHashCodeByKey:key];
self
.keys[i]!=[
NSNull
null];i=(i+1)%
self
.capticity) {
if
([
self
.keys[i] isEqualToString:key]) {
self
.values[i]=value;
return
;
}
}
self
.keys[i]=key;
self
.values[i]=value;
self
.count=
self
.count+1;
}
-(
NSString
*)getValue:(
NSString
*)key{
for
(
NSInteger
i=[
self
getHashCodeByKey:key];
self
.keys[i]!=
NULL
; i=(i+1)%
self
.capticity) {
if
([
self
.keys[i] isEqualToString:key]) {
return
self
.values[i];
}
}
return
NULL
;
}
@end
|
相比上面的拉链法,此处多了一个resize,以免N接近于M的时候效率很低,N最好小于M的1/2~
测试代码:
1
2
3
4
5
6
7
8
9
10
|
LinearHashTable *hashTable=[[LinearHashTable alloc]initWithData:12];
[hashTable putData:@
"2"
value:@
"FlyElephant"
];
[hashTable putData:@
"3"
value:@
"原文地址:http://www.cnblogs.com/xiaofeixiang"
];
[hashTable putData:@
"15"
value:@
"博客园"
];
[hashTable putData:@
"6"
value:@
"技术交流:228407086"
];
[hashTable putData:@
"9"
value:@
"keso"
];
[hashTable putData:@
"12"
value:@
"FlyElephant"
];
[hashTable putData:@
"13"
value:@
"北京"
];
NSString
*temp=[hashTable getValue:@
"12"
];
NSLog
(@
"博客园:%@"
,temp);
|
效果如下:
本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4677285.html,如需转载请自行联系原作者