iOSiOS学习笔记iOS Developer

iOS 数据统计优化策略 字符串转大数 OC类似java的has

2017-05-22  本文已影响135人  熊猫人和熊猫君

需求:背景减低服务器存储压力,优化客户端上报数据大小用于节省用户网络。这个就需要字符串转大树或者转枚举。字符串md5转为一个32位的大数,降低服务器存储空间,优化客户端发送数据量

在java里面实现比较简单,底层提供了hashcode接口

@Override public int hashCode() {
        int hash = hashCode;
        if (hash == 0) {
            if (count == 0) {
                return 0;
            }
            final int end = count + offset;
            final char[] chars = value;
            for (int i = offset; i < end; ++i) {
                hash = 31*hash + chars[i];
            }
            hashCode = hash;
        }
        return hash;
    }

在iOS里模仿java实现一个

- (int64_t)convertStringToBigNumberInt64:(NSString *)string
{
    if (string == nil || string.length == 0 )
    {
        return 0;
    }
    
    int i = 0;
    int64_t hash = 0;
    
    const char * charString =[string UTF8String];
    for (i = 0; i < strlen(charString); i++) 
   {
       hash = hash * 31 + charString[i];
   }
   
    return hash % INT64_MAX;
}

当然iOS中NSString 有一个接口为hash返回可返回类似的大数,

 */
#define HashEverythingLimit 96

#define HashNextFourUniChars(accessStart, accessEnd, pointer) 
    {result = result * 67503105 + (accessStart 0 accessEnd) * 16974593  + (accessStart 1 accessEnd) * 66049  + (accessStart 2 accessEnd) * 257 + (accessStart 3 accessEnd); pointer += 4;}
#define HashNextUniChar(accessStart, accessEnd, pointer) 
    {result = result * 257 + (accessStart 0 accessEnd); pointer++;}

CF_INTERNAL CFHashCode __CFStrHashCharacters(const UniChar* uContents, CFIndex len, CFIndex actualLen) {
    CFHashCode result = actualLen;
    if (len <= HashEverythingLimit) {
        const UniChar* end4 = uContents + (len & ~3);
        const UniChar* end = uContents + len;
        while (uContents < end4) {
            HashNextFourUniChars(uContents[, ], uContents); // First count in fours
        }
        while (uContents < end) {
            HashNextUniChar(uContents[, ], uContents); // Then for the last <4 chars, count in ones...
        }
    } else {
        const UniChar* contents, * end;
        contents = uContents;
        end = contents + 32;
        while (contents < end) {
            HashNextFourUniChars(contents[, ], contents);
        }
        contents = uContents + (len >> 1) - 16;
        end = contents + 32;
        while (contents < end) {
            HashNextFourUniChars(contents[, ], contents);
        }
        end = uContents + len;
        contents = end - 32;
        while (contents < end) {
            HashNextFourUniChars(contents[, ], contents);
        }
    }
    return result + (result << (actualLen & 31));
}

由源码可知道,字符串的长度如果大于96,其策略为取前32位 取中段32位 后取后端32位,在取值为准字符相同的情况下,其他任意位置的字符发生改变,Hash值都不会变。字符串的长度如果小于等于96,所有字符将参与运算,也就是说96个字符改变其中任意一个都将导致hash值的变化。

当然不是所有的32位都能满足,有时候需要用64位来降低碰撞概率,有时候32位过多,只需要16位2个字节的,可以根据上面算法自己调整或者求模运算保bigNumber落在特定的整形数范围内。

源码来自,https://github.com/DmitrySkiba/itoa-cleancf/blob/9e20484344430008a8b1a0e7c0f29aa06eac3d1e/src/CoreFoundation/CFString/CFString_Hash.c

上一篇下一篇

猜你喜欢

热点阅读