算法-散列表

散列表(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,如需转载请自行联系原作者

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值