iOS 中isEqual和Hash的笔记(一)

iOS  中isEqual和Hash的笔记(一)

HashABC

hash是一种用于处理查找时非常高效的数据结构。时间复杂度一般情况下可以直接认为是O(1)。

散列技术是在记录的存储位置和它的关键字之间确立一个对应关系 f,使得关键字 key对应的存储位置 f(key)。函数 f被称之为哈希函数(hash function),使用哈希技术将数据存储在一块连续的地址区域中,该连续的存储空间我们称之为散列表,也就是哈希表(hash table)。

我们在存储的时候,是用过哈希函数计算得到哈希地址,并按照哈希地址存储该记录;查找的时候,通过通过同样的哈希函数计算记录的哈希地址,并按照地址访问该记录。

如果两个值在一个地址,就是 冲突(collision)。

解决冲突的方法主要是下边几种

  • 开放定址法
  • 再散列函数法
  • 链地址法(拉链法)
  • 公共溢出区法

假如在理想的状态下完全没有冲突,哈希表是所有查找中性能最高的,但是在极端情况下(全是一个地址),就是一个链表(链地址法)了。

测量性能我们主要是以下边几个标准:

  • 散列表是否均匀
  • 处理冲突的方式
  • 散列表的负载因子
    负载因子 = 表中记录个数 / 散列表的长度

优点:在理想的状态下,查找、插入、删除操作的效率是最高的,是O(1),树的相同操作也是需要O(n)的时间级的。

缺点:要时刻注意散列表的负载因子,准备扩容;要在面对真实的场景的时候,采用正确的冲突处理方法。

对象等同性

哈希表在iOS中使用时相当多的,比如说weak的地址就是由一个哈希表实现的,NSDictionary和NSSet的底层实现也是哈希表,NSObject也有hash值(但是要特别注意,这几种的hash实现并不相同)。与其说巧合,不如说这表明了在移动开发中的一种思想:

响应时间是比内存空间相对更重要的东西。移动端的App是面向用户的,用户体验最直观的体现就是时间!响应时间、动画流畅度、屏幕帧数等等,都是这一思想的体现,而在很多优秀的第三方,也都使用了这一思路。当然,这一思想的主要也会造成很多问题,比如说内存暴涨以及OOM问题,这就是另外的问题了。

话回正题。

“==”代表的是两个对象的指针的直接对比两个对象的指针,也就是内存地址;而“isEqual”是对比对象的值。以下边代码为例:

NSString *stringA = @"BiBoyang";  NSMutableString *stringB = [stringA mutableCopy];  
  BOOL equalA = (stringA == stringB);//0
  BOOL equalB = [stringA isEqual:stringB];//1
  BOOL equalC = [stringA isEqualToString:stringB];//1

可以发现,在比较对象的指针的时候,是不相同的;但是在直接对比对象的值的时候,是相等的。

在 NSObject.h中,我们可以看到这种两个重要的方法。

- (BOOL)isEqual:(id)object;
@property (readonly) NSUInteger hash;

这里需要注意的是,如果isEqual判断两个对象相等,则两个对象的hash值相同;反之则不然。这里是在其他语言,比如Java中也是一样的&#x