NSDictionary 、NSSArray、NSSet
NSSArray
用于对象有序集合(NSObject对象)
NSSet
用于对象的无序,不重复集合
NSDictionary
无序键值映射
以上为不可变
可变的为以下三种
NSMutableArray
NSMutableSet
NSMutableDictionary
实现原理
NSDictionary
(字典)是使用哈希表 Hash table
(也叫散列表)来实现的。哈希表是根据键(Key)而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键(key)值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做哈希表。也就是说哈希表的本质是一个数组,数组中每一个元素其实就是NSDictionary
键值对。
若关键字为k
,则其值存放在f(k)
的存储位置上。由此,不需比较便可直接取得所查记录。称这个对应关系f为哈希函数。
哈希冲突(哈希碰撞):如果关键字k
不同,但是通过哈希函数f(k)
得到的结果是一样的,这样就会出现哈希冲突,也就是说,得到的这个地址有可能已经存在键值对了。
解决冲突:哈希冲突的解决方案有如下多种方式
- 开放定址法(发生冲突,继续寻找下一块未被占用的存储地址)
- 再散列函数法
- 链地址法,而JAVA中的HashMap即是采用了链地址法来解决冲突,也就是数组+链表的方式.
链地址法的大概原理如下
简单来说,HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。
如下所示,位置1、3、5都是有冲突的。
哈希表的查找效率
影响哈希表的查找效率主要问题是冲突问题,如果冲突较多,查找效率就会低。
冲突原因主要是以下三个
哈希函数是否均匀;
哈希冲突处理的方法;
哈希表的负载因子 。
哈希表的负载因子 = 填入表中的元素个数 / 哈希表的长度
也就是说,哈希表越满,负载因子越大。
面试题
Q:当用一个不存在的key来查找两个不同长度的字典,那么哪个效率会高?
A:表面上看可能是一样快,因为字典底层都用了哈希表,查找的时间复杂度为 O(1),(最差的时候是O(n))都是一样的,但是可能会由于两个哈希表的负载因子不同,倒是查找的时间也是不同的。