• 算法-散列表


    散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组就是散列表。散列表是算法上时间和空间做出权衡的例子,如果没有内存限制,我们可以直接将键作为数据的索引直接一次访问即可,如果没有时间限制我们直接通过之前的无序数组进行顺序查找即可。散列函数能够直接将关键字转化成索引,但是会出现相同索引的情况,这个时候我们需要处理冲突碰撞,我们会使用到拉链法和线性探测法解决碰撞问题。

    拉链法

    将整数散列最常用的就是除留余数法,浮点数字可以转为二进制数字然后使用除留余数法,字符串可以通过Horner的算法计算散列值,本文就简单的通过整数进行散列然后通过拉链法解决碰撞,需要用到本人之前的文章的算法-符号表的实现(顺序查找和二分查找):

    @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
    

     实现代码:

    @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
    

     测试代码:

            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分为两个数组实现,类似于符号表的二分查找:

    @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  

    实现代码:

    @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~

    测试代码:

            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);

    效果如下:

  • 相关阅读:
    RecyclerView中装饰者模式应用
    Android中的Drawable和动画
    Android的线程和线程池
    Bitmap的加载和Cache
    Android的消息机制
    【Java基础】线程和并发机制
    Asp.Net 将HTML中通过dom-to-image.js标签div内的内容转化为图片保存到本地
    Asp.Net MVC @Html.TextBox 只允许输入数字问题
    程序员编程10大原则,请牢牢记住
    Asp.Net MVC WebAPI的创建与前台Jquery ajax后台HttpClient调用详解
  • 原文地址:https://www.cnblogs.com/xiaofeixiang/p/4677285.html
Copyright © 2020-2023  润新知