IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> OC中NSDictionary、NSArray及Swift中Array底层实现原理 -> 正文阅读

[数据结构与算法]OC中NSDictionary、NSArray及Swift中Array底层实现原理

首先我们先了解哈希表(hash表)这个概念:

哈希表(hash表):又叫做散列表,是根据关键码值(key value)而直接访问的数据结构。也就是它通过关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射叫做函数,存放记录的数组叫做哈希表。

读到此处我们得到一个关键信息:所谓?哈希表就是一个数组?,数组中每一个元素称为一个箱子(bin),箱子中存放的是键值对。

hash表存储过程简单介绍:

1.根据key值计算出它的hash值h;

2.假设箱子的个数是n,那么键值对应该放在第(h%n)个箱子中。

3.如果该箱子中已经有了键值对,就是用开放寻址法或者拉链法解决冲突,使用拉链法解决哈希冲突时,每个箱子其实是一个链表,属于同一个箱子的所有键值对都会排列在链表中。

依此我们得出结论:OC中的字典其实是一个数组,数组中每一个元素同样为一个链表实现的数组,也就是数组中套数组。

一、NSDictionary使用原理

在OC中NSDictionary是使用hash表来实现key和value的映射和存储的。

NDDictionary内部结构:

typedef struct {
   NSMapTable        *table;
   NSInteger          i;
   struct _NSMapNode *j;
} NSMapEnumerator;

?NSMapTable是一个哈希+链表的数据结构

hash表的实现

NSDictionary生成hash表使用的是拉链法

根结构为数组,每个元素为链表

添加key的时候,会把key的hash对根结构的长度取余,结果作为根结构的下标,再把key插入到下标对应的链表元素中。

解决hash冲突

hash冲突即存在多个hash一样的key

拉链法解决冲突:大概原理就是将同一个存储位置的所有元素保存在一个链表中。?

一般来说拉链法需要涉及到解决hash冲突,但巧就巧在,ObjC中一般对象的hash就是它本身的地址,所以几乎是不可能冲突的,对于NSString这类重写了hash方法的,会同时要求重写isEqual方法。当真的遇到hash冲突的话,NSDictionary插入时会无视冲突,而在取数据时,在找到hash后会多一步通过isEqual对比是不是需要的key,如果不是就继续往下找,一般来说出现hash冲突的key都会在同一个链表的相邻位置,所以查找的消耗会非常的低

通俗的说法:那么对应在oc中字典具体如何进行存储的呢?

在oc中每一个对象创建时,都默认生成一个hashCode,也就是经过hash算法生成的一串数字,当利用key去取字典中的value时,若是使用遍历或者二分查找等方法,效率相对较低,于是出现了根据每一个key生成的hashCode将键值对放到hasCode对应的数组中的指定位置,这样当用key去取值时,便不必遍历去获取,既可以根据hashCode直接取出。注意:key值取余得到值相等的键值对,都将保存在同一个链表数组中,当查找key对应的值时,首先获取到该链表数组,然后遍历数组,取正确的key所对应的值即可。

一、NSArray使用原理

如果学过数据结构(这个对了解底层非常重要!),就知道,他是一个线性表数据结构,与之,链表,队列,栈也是。还有一种数据结构为非线性表,例如图,堆,二叉树。区别就在于线性表中,有前后关系:

阅读《Effective Objective-C 2.0》的原版的时候

在使用了NSArray的alloc方法来获取实例时,该方法首先会分类一个属于某类的实例,此实例充当“占位数组”。该数组稍后会转为另一个类的实例,而那个类则是NSArray的实体子类。

?不管创建的事可变还是不可变的数组,

在alloc之后得到的类都是 __NSPlaceholderArray。

而当我们init一个不可变的空数组之后,得到的是**__NSArray0**;

如果有且只有一个元素,那就是 __NSSingleObjectArrayI;

有多个元素的,叫做 __NSArrayI;

init出来一个可变数组的话,都是 __NSArrayM。

CFArray和NSMutableArray

CFArray是CoreFoundation中的,和Foundation中的NSArray相对应

任何典型的程序员都知道 C 数组的原理。可以归结为一段能被方便读写的连续内存空间。数组和指针并不相同 ,不能说:一块被 malloc过的内存空间等同于一个数组 (一种被滥用了的说法)。

NSMutableArray 是一个类簇 - 具体实现实际上是其子类 __NSArrayM

@interface __NSArrayM : NSMutableArray
{
    unsigned long long _used;
    unsigned long long _doHardRetain:1;
    unsigned long long _doWeakAccess:1;
    unsigned long long _size:62;
    unsigned long long _hasObjects:1;
    unsigned long long _hasStrongReferences:1;
    unsigned long long _offset:62;
    unsigned long long _mutations;
    id *_list;
}

__NSArrayM 使用了环形缓冲区(Circular buffer) 这个数据结构相当简单, 只是比常规数组和缓冲区复杂点. 环形缓冲区的内容能在到达任意一端时绕向另一端.
环形缓冲区在任意一端插入或删除均不会要求移动任何内存(除非缓冲区满了)

如果我们在中间进行插入或者删除,只会移动最少的一边的元素。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-07-15 16:28:07  更:2021-07-15 16:30:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/4 10:30:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码