数组与集合面试题

1. OC 有哪些集合类型

集合定义:由一个或多个确定的元素构成的整体叫做集合

数学集合三大特性

  • 确定性
  • 互异性
  • 无序性

NSArray, NSSet, NSOrderedSet 和 NSDictionary NSMapTable, NSHashTable, NSPointerArray

NSSet 讲解

对于编程语言来说无法在编译时就确定元素是否互异性,因此可以添加相同的元素。但内部对添加只会保留一个。

请添加图片描述

  • 我们放了三个NSNumber ,但是编译器不会报错,并且在内部保持了集合的统一性。
  • NSSet是无序的

或许发现上面怎么操作都是3,5,1,4,虽然每次输出一致,但打印与我们代码中放的位置没有关联

仅把Set当做一个没有顺序也没有索引的对像集合即可

  • 集合更灵活,并且检查元素是否存时比数组更加灵活
  • 对于可变的数组和集合来说,集合增删更快

数组

可变与不可变它们的本质,还是因为它们在内存储存方式不同

不可变数组(不属于集合类型)

将数据元素存在一片连续的地址空间

  • 数组的地址时其首元素地址,即a[0]的地址,
  • 并且数组时连续的,我们可以方便查找出任意元素所在位置
不可变数组查找

比如想要查找a[5],通过计算a[0]+5xsizeof(T),T为数组每个元素的类型,时间复杂度0(1)

数组不可变的原因

是为了避免增删操作要对后续元素的进行调整,但但保持了数据查找快的特点

可变数组

可变数组的数据结构是用的链表

链表是会存在与不连续的地址空间,而且会存在与一些可用的地址碎片中。

可变数组查找

需要从头到尾查找个遍,时间复杂度为0(N)

但是链表删除元素比较快

字典与哈希表

哈希表又称为散列表,是根据关键码值而直接进行访问的数据结构,即通过关键码将值映射到表中的某个位置来存储和访问的,以加快查找速度。

哈希表是字典实现的原理,字典通过哈希表来存储数据,读取的时候也是通过哈希表来获取对应的值,

查找

无论哈希表中有多少数据,增删操作事件复杂度都是0(1),

存储键值对

字典的键一般为字符串,字符串会有特定的方式来获取特定的哈希值,保证键的唯一性,

将键通过特性的哈希函数,获取到哈希值,然后根据哈希值可以找到数据在字典中的位置,并其返回在内存中的地址。

NSMapTable

与 NSMapTable 对应的,是 NSMutableDictionary。除了 集合的共有特点以外,比起传统字典,它还有一些优势:

  • key 可以不用遵循 NSCopying 协议;
  • key 和 value 的内存管理方式可以分开,如:key 是强引用,value 是弱引用;

当用 weak 修饰 key 或 value 时,有一方被释放,则该键值对移除。

NSHashTable

NSHashTable 对应 NSMutableSet,它的 API 更为简单,与 NSMapTable 同样,初始化方法的
capacity 并未生效。

NSHashTable 有一个 allObjectes 的属性,返回 NSArray,即使 NSHashTable 是弱引用成员,allObjects 依然会对成员进行强引用。

NSPointerArray

NSPointerArray和NSArray/NSMutableArray一样,用于有序的插入或移除。不同的是:

  • 可以存储 nil,并且 nil 还参与 count 的计算。
  • count 值可以直接设置,如果直接设置count,那么会使用 nil 占位。
  • 可以使用 weak 来修饰元素,可以添加所有的指针类型。
  • 可以通过 for…in 来进行遍历。

也有一些缺点:

  • 操作均基于 index,无法通过 object 来进行操作;
  • 无法直接插入 array,或用 array 初始化;
  • 查找功能没有 NSArray 强大;
  • 没有逆序、排序等 API 提供

2.数组不可变跟可变数据内存开辟的有什么区别

不可变

  • 将数据元素存在一片连续的地址空间
  • 数组的地址时其首元素地址,即a[0]的地址,
  • 并且数组时连续的,我们可以方便查找出任意元素所在位置

可变

  • 可变数组的数据结构是用的链表
  • 链表是会存在与不连续的地址空间,而且会存在与一些可用的地址碎片中。
  • 需要从头到尾查找个遍,时间复杂度为0(N)
  • 但是链表删除/增加元素比较快

2.1数组不可变为什么不可变

  • 赋值之后内存没办法扩展
  • 是为了避免增删操作要对后续元素的进行调整,但但保持了数据查找快的特点

3. NSCache 与 字典 的区别

NSCache是系统提供的一种类似于集合(NSMutableDictionary)的缓存,它与集合的不同如下:

  • NSCache具有自动删除的功能,以减少系统占用的内存;
  • NSCache是线程安全的,不需要加线程锁;
  • 键对象不会像 NSMutableDictionary 中那样被复制。(键不需要实现 NSCopying 协议)。
  • 多个线程可以同时访问NSCache。
  • NSCache可以指定缓存的限额,当缓存超出限额自动释放内存 缓存限额:
  • NSCache在系统发出低内存通知时,会自动删除缓存。

4.NSDictionary字典的原理?追问重复的key是怎么排列的?取的时候是怎么取的?

字典通过使用- (void)setObject:(id)anObject
forKey:(id)aKey;方法,用Hash表来实现key和value之间映射和存储的。
哈希概念:哈希表本质是一个数组,每一个元素称为一个箱子,而箱子里面的存放的是键值对。 哈希表(Hash
Table)也叫做散列表,这是根据关键码(key vlaue)而直接进行访问的数据结构。换句话说,通过把关键码映
射到表里面的一个位置来访问记录,用来加快查找的速度。映射的函数就叫做散列函数,存放记录的数组也叫做散列表。

哈希存储过程

3.1 首先根据key计算出它的哈希值h
3.2 如果箱子的个数为n,那么key值是应该放在第(h%n)个箱子中
3.3 如果该箱子已经有了值,就使用开放寻址法或者拉链法进行解决冲突。 如果我们在使用拉链法解决哈希冲突时候,每个箱子都是一个链表,属于同一个箱子的所有键值都会排列在链表中。

5.NSArray与NSSet的区别?

  • NSArray内存中存储地址连续,而NSSet不连续
  • NSSet效率高,内部使用hash查找;NSArray查找需要遍历
  • NSSet通过anyObject访问元素,NSArray通过下标访问

6.NSHashTable与NSMapTable?

  • NSHashTable是NSSet的通用版本,对元素弱引用,可变类型;可以在访问成员时copy
  • NSMapTable是NSDictionary的通用版本,对元素弱引用,可变类型;可以在访问成员时copy

(注:NSHashTable与NSSet的区别:NSHashTable可以通过option设置元素弱引用/copyin,只有可变类型。但是添加对象的时候NSHashTable耗费时间是NSSet的两倍。
NSMapTable与NSDictionary的区别:同上)

7.NSArray的存储形式、有哪几种存储形式?

  • 实际的数组元素被存储在堆(heap)内存中;
  • 数组引用变量是一个引用类型的变量,被存储在栈(stack)内存中

数组就是在内存中开辟一块连续的、大小相同的空间,用来存储数据。 连续:内存地址是连续的

8.可变数组的实现原理?

不管创建的事可变还是不可变的数组,在alloc之后得到的类都是 __NSPlaceholderArray。而当我们init一个不可变的空数组之后,得到的是**__NSArray0**;如果有且只有一个元素,那就是 __NSSingleObjectArrayI;有多个元素的,叫做 __NSArrayI;init出来一个可变数组的话,都是 __NSArrayM。

我们看到__NSPlaceholderArray的名字就知道它是用来占位的。

循环缓冲区(也称为环形缓冲区)是固定大小的缓冲区,工作原理就像内存是连续的且可循环的一样。在生成和使用内存时,不需将原来的数据全部重新清理掉,只要调整head/tail 指针即可。当添加数据时,head 指针前进。当使用数据时,tail 指针向前移动。当到达缓冲区的尾部时,指针又回到缓冲区的起始位置。

9.问 从字典中取数据,为什么比在数组中取数据快,底层原理是什么?

Hash 与数组的区别

10.NSCache和NSMutableDictionary的相同点与区别?

NSCache和NSMutableDictionary功能用法基本是相同的
NSCache是线程安全的,NSMutableDictionary线程不安全,Mutable开发的类一般都是线程不安全的
当内存不足时NSCache会自动释放内存(所以从缓存中取数据的时候总要判断是否为空)
NSCache可以指定缓存的限额,当缓存超出限额自动释放内存,NSCache 是一个容器类,类似于NSDIctionary,通过key-value 形式存储和查询值,用于临时存储对象。
NSCache的Key只是对对象进行了Strong引用,而非拷贝,所以不需要实现NSCopying协议
NSCache胜过NSDictionary之处在于,当系统资源将要耗尽时,它可以自动删减缓存。如果采用普通的字典,那么就要自己编写挂钩,在系统发出“低内存”通知时手工删减缓存。
NSCache并不会“拷贝”键,而是会“保留”它。此行为用NSDictionary也可以实现,然而需要编写相当复杂的代码。NSCache对象不拷贝键的原因在于:很多时候,键都是不支持拷贝操作的对象来充当的。因此,NSCache不会自动拷贝键,所以说,在键不支持拷贝操作的情况下,该类用起来比字典更方便。另外,NSCache是线程安全的,而NSDictionary则绝对不具备此优势

11. NSMapTable

_objectInfosMap根据retainObserved进行NSMapTable内存管理/初始化配置,FBKVOController的成员变量。其中保存的是一个被观察者对应多个_FBKVOInfo(也就是被观察对象对应多个keyPath):

 NSMapTable<id, NSMutableSet<_FBKVOInfo *> *> *_objectInfosMap;
1

_FBKVOInfo是放在NSMutableSet中的,说明是去重的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值