算法-散列表
散列表(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); |
效果如下:
作者:FlyElephant
出处:http://www.cnblogs.com/xiaofeixiang
说明:博客经个人辛苦努力所得,如有转载会特别申明,博客不求技惊四座,但求与有缘人分享个人学习知识,生活学习提高之用,博客所有权归本人和博客园所有,如有转载请在显著位置给出博文链接和作者姓名,否则本人将付诸法律。
出处:http://www.cnblogs.com/xiaofeixiang
说明:博客经个人辛苦努力所得,如有转载会特别申明,博客不求技惊四座,但求与有缘人分享个人学习知识,生活学习提高之用,博客所有权归本人和博客园所有,如有转载请在显著位置给出博文链接和作者姓名,否则本人将付诸法律。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 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的设计模式综述