算法-散列表

散列表(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,nonatomicNSMutableArray  *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);

效果如下:

posted @   Fly_Elephant  阅读(1095)  评论(2编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述
点击右上角即可分享
微信分享提示