ios常用演算法
㈠ iOS面試題12-數據結構演算法篇
《 2018 iOS面試題系列 》
這里沒有圖啊,大家可以抽象一下。
數據結構的存儲一般常用的有兩種 順序存儲結構 和 鏈式存儲結構
發揮想像力啊。 舉個列子。數組。1-2-3-4-5-6-7-8-9-10。這個就是一個順序存儲結構 ,存儲是按順序的 舉例說明啊。 棧。做開發的都熟悉。棧是先進後出 ,後進先出的形式 對不對 ?!他的你可以這樣理解
hello world 在棧裡面從棧底到棧頂的邏輯依次為 h-e-l-l-o-w-o-r-l-d 這就是順序存儲 再比如 隊列 ,隊列是先進先出的對吧,從頭到尾 h-e-l-l-o-w-o-r-l-d 就是這樣排對的
再次發揮想像力 這個稍微復雜一點 這個圖片我一直弄好 ,回頭找美工問問,再貼上 例如 還是一個數組
1-2-3-4-5-6-7-8-9-10 鏈式存儲就不一樣了 1(地址)-2(地址)-7(地址)-4(地址)-5(地址)-9(地址)-8(地址)-3(地址)-6(地址)-10(地址)。每個數字後面跟著一個地址 而且存儲形式不再是順序 ,也就說順序亂了,1(地址) 1後面跟著的這個地址指向的是2,2後面的地址指向的是3,3後面的地址指向是誰你應該清楚了吧。他執行的時候是 1(地址)-2(地址)-3(地址)-4(地址)-5(地址)-6(地址)-7(地址)-8(地址)-9(地址)-10(地址),但是存儲的時候就是完全隨機的。明白了?!
還是舉例子。理解最重要。不要去死記硬背 哪些什麼。定義啊。邏輯啊。理解才是最重要滴
二叉樹有五種表現形式
二叉樹可以轉換成森林 樹也可以轉換成二叉樹。這里就不介紹了 你做項目絕對用不到
數據結構大致介紹這么多吧。理解為主, 別死記,死記沒什麼用
從現在開始介紹演算法啊
二叉樹這個比較麻煩 還有平衡二叉樹 有點繞 如果不懂二叉樹這一塊 你是百分之二百看不懂的
原文鏈接
㈡ IOS 演算法(中級篇) ----- 無重復字元的最長子串
輸入: s = "abcabcbb"
輸出: 3
解釋: 因為無重復字元的最長子串是 "abc",所以其長度為 3。
輸入: s = "bbbbb"
輸出: 1
解釋: 因為無重復字元的最長子串是 "b",所以其長度為 1。
輸入: s = "pwwkew"
輸出: 3
解釋: 因為無重復字元的最長子串是 "wke",所以其長度為 3。
請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。
輸入: s = ""
輸出: 0
題意稍微解釋下, 找到給定字元串中 最長 , 不含重復字母 子串
以 "abcabcbb" 舉例, 例如:
① "a", "b", "c", "ab", "bc"...連續的都為子串, 像"abb"這種不為子串
② "a", "b", "c", "ab", "bc"為子串, 但都不是最長, 所以不滿足罩襲
③ "abca"也為子串, 也很長, 但含重復字母 a , 固也不滿足條件
④ "abc", "bca", "cab", 這種物衡兄最長且不含重復字母滿足條件
利用 遍歷法攔緩 + swift自帶函數解題
定義一個容器數組存儲每次遍歷的字元, 如果包含則刪除數組內包含之前所有元素
找當前與之前最大取最大即可
以 "abcabcbb" 舉例
那麼有
firstIndex:
removeFirst
㈢ iOS-數組排序
首先提供一些排序文章供大家參考學習
常用排序演算法總結
iOS-八大基本排序
Sort 各類算前悄卜法和時間復雜度分析
關於iOS中,我們有自己的"sort」尚方寶劍,主要涉及的有NSComparisonResult和compare
NSComparisonResult 是一個枚舉類型裡麵包慧穗含三個值
NSOrderedAscending = -1L,表示兩個比較的對象前者小於後置
NSOrderedSame, 表示比較的對象相等
NSOrderedDescending表示兩個比較的對象前者大於後者
字元串比較大小的函數,返回NSComparisonResult
數組排序方法(升序)
數組排序方法
數組排序方法(亂序)
單關鍵字排序
多關鍵字排序
其中ascending為YES表示升序排列
詳細也可看這篇文章分享 iOS淺析排序規運型則描述類: NSSortDescriptor
㈣ ios SKU 組合演算法
通俗來講,一個SKU 就是商品在規格上的一種組合,比如說,一件衣服 有紅色 M號的 也有藍色 L號的 ,不同的組合就是不同的SKU
近段時間,剛好遇到要在商品詳情頁購買商品的時候,實現選擇不同規格組合的sku,預判無庫存sku選項置灰,減少客戶不必要sku的選擇。
網上搜尋了一大批有關sku選擇演算法的文章,然後被各路大神的一頓操作秀得一臉懵逼,簡單來說就是沒看懂。。。
當然基於以上參考得到的靈感,終於總結出來了一種簡單易用通俗易懂的sku選擇演算法,思路簡單,唯一的bug是sku數據有n多層的時候,計算量大耗內存。當然現在手機的運算能力都是杠杠的,正常來說商品的sku也不會有幾十上百層那麼誇張。
接下來我先捋一下思路吧!
Tips: sku 有三種狀態,可選(正常),不可選(置灰),已選中(高亮),
一,sku演算法初版:計算所有sku的組合 與 有庫存sku的組合的交集,交集裡面的sku為可選項,反之其他sku為不可選。
1.計算所有sku的組合-->集合A
A = ["34,61,66" , "34,61,67" , ......]
2.計算有庫存的sku的組合 -->集合B
一般是從後台伺服器返回的 eg:
3. 計算集合A與集合B的交集,交集裡面的所有元素就是初始時所有可選sku ID ,反之其他sku ID就是置灰(無庫存不可選狀態)
4.以上三步就是簡易的sku演算法核心思路,彈出規格框時,計算集合A和集合B的交集,得到初步賽選結果,告訴客戶,哪些sku無庫存不可選置灰顯示,可選的為正常狀態顯示,減少客戶做不必要的選擇操作。
5.當然,細心的你很快就會發現這樣的sku演算法會導致無法判斷出,已選sku的兄弟節點是否可選的bug。
二,優化兄弟節點的可選狀態判斷bug
1.如上圖 已選Platform 屬性的 34,長度屬性的 62 , 我們要判斷的已選sku兄弟節點屬性分別是Platform 屬性的 35,長度屬性的 61。
2.即:
要判斷 長度屬性的 61是否為可選,就要判斷,34,61這樣的組合是否屬於有庫存組合裡面子集,是:可選,不是: 不可選。
同理:
要判斷 Platform 屬性的 35是否為可選,就要判斷,35,62這樣的組合是否屬於有庫存組合裡面子集,是:可選,不是: 不可選。
3.細心的你肯定發現了規律,34,61 或者 35,62 這樣的組合都有一個共同點
即:包含n個已選skuID,n = 已選sku個數-1 .
三,計算兄弟節點是否可選
1,計算已選sku ID 同類屬性的組合 ==集合C 即:計算Platform 屬性和長度屬性的組合
集合C = ["34,61","34,62","35,61","35,61","35,62"]
2.計算已選skuID的子集 ==集合D 即:計算 [34,62]的子集
集合D = ["34","62","34,62"]
3.從集合D裡面篩選出,含有n個已選skuID的子集(n = 已選sku個數-1 )==集合E
集合E = ["34","62"]
4.最後計算可選兄弟節點組合,集合C裡面的組合只要是含有集合E裡面的元素都是可選兄弟節點組合
可選兄弟節點組合F = 【集合C裡面的組合只要是含有集合E裡面的元素】
5.
兄弟節點可選skuID = 【(集合A與集合B的交集的skuID集合)再與 集合F 的並集 】
四,整理
1.篩選有庫存的sku組合為可選sku 其餘為不可選sku
2.計算兄弟節點可選sku
3.可選sku正常顯示,不可選sku置灰,已選sku高亮
附Demo: sku演算法demo
五,拓展一下
㈤ IOS 演算法(中級篇) ----- 無重復字元串的排列組合
例:
給定: s = "qwe"
返回:["qwe", "qew", "wqe", "weq", "ewq", "eqw"]
給定: s = "ab"
返回:["ab", "ba"]
解題思路
這個題目蔽旁比較好的地方是規定了 字元串每個字元均不相同, 減少了我們很多判斷處理
全排列+交換法, 交換位置之後再遞歸回溯
例如 初始字元串 qwe, 我們定義一個index = 0, 初始數組, [qwe]
第一輪,數組每個元素用index 0以上的,跟0做交換,得到:
wqe, eqw 加上初始qwe, 我們得到這樣一個侍埋數組 [qwe, wqe, eqw]
第二宏談橡輪,新數組每個元素用index 1以上的,跟1做交換,得到:
qew, weq, ewq, 加上之前那些 得到 [qwe, wqe, eqw, qew, weq, ewq]
為了便於理解我們再看個例子 初始字元串 JQKA, index = 0, [JQKA]
第一輪,index 0以上的,跟0做交換,得到:
QJKA, KQJA, AQKJ
數組: [JQKA, QJKA, KQJA, AQKJ]
第二輪,index 1以上的,跟1做交換,得到:
JKQA, JAKQ, QKJA, QAKJ, KJQA, KAJQ, AKQJ, AJKQ
數組: [JQKA, QJKA, KQJA, AQKJ, JKQA, JAKQ, QKJA, QAKJ, KJQA, KAJQ, AKQJ, AJKQ]
第三輪,index 2以上的,跟2做交換,得到:
JQAK QJAK KQAJ
AQJK JKAQ JAQK
QKAJ QAJK KJAQ
KAQJ AKJQ AJQK
數組: [JQKA, QJKA, KQJA, AQKJ, JKQA, JAKQ, QKJA, QAKJ, KJQA, KAJQ, AKQJ, AJKQ, JQAK QJAK KQAJ, AQJK JKAQ JAQK, QKAJ QAJK KJAQ, KAQJ AKJQ AJQK]
完成返回
按著這個思路我們可寫演算法
㈥ iOS演算法系列(二)- 八大排序演算法
排序演算法也算是老生常談了,如果你大學專業是計算機或軟體,甚至你參加過國二國三都會學到排序演算法,如果我沒猜錯的話你接觸的第一個演算法是冒泡。
排序演算法老生常談,但確實多少大廠面試題中的必考題。
廢話不多說,開始正題
常見的八種排序演算法他們的關系如下:
遞歸的最底部情形,是數列的大小是零或一,也就是永遠都已經被排序好了。雖然一直遞歸下去,但是這個演算法總會退出,因為在每次的迭代(iteration)中,它至少會把一個元素擺到它最後的位置去。
希爾排序是基於插入排序的以下兩點性質而提出改進方法的:
插入排序在對幾乎已經排好序的數據操作時, 效率高, 即可以達到線性排序的效率
但插入排序一般來說是低效的, 因為插入排序每次只能將數據移動一位
希爾排序的基本思想是:先將整個待排序的記錄序列分割成為若乾子序列分別進行直接插入排序,待整個序列中的記錄「基本有序」時,再對全體記錄進行依次直接插入排序。
說基數排序之前,我們簡單介紹桶排序:
演算法思想:是將陣列分到有限數量的桶子里。每個桶子再個別排序(有可能再使用別的排序演算法或是以遞回方式繼續使 用桶排序進行排序)。桶排序是鴿巢排序的一種歸納結果。當要被排序的陣列內的數值是均勻分配的時候,桶排序使用線性時間(Θ(n))。但桶排序並不是 比較排序,他不受到 O(n log n) 下限的影響。
簡單來說,就是把數據分組,放在一個個的桶中,然後對每個桶裡面的在進行排序。
例如要對大小為[1..1000]范圍內的n個整數A[1..n]排序
各種排序的穩定性,時間復雜度、空間復雜度、穩定性總結如下圖:
㈦ IOS AES加密
AES加密有四種工作模式:ECB、CBC、CFB和OFB,其中IOS支持ECB(kCCOptionPKCS7Padding 對應Java中的kCCOptionPKCS5Padding)和CBC(kCCOptionECBMode)
AES是開發中常用的加密演算法之一。然而由於前後端開發使用的語言不統一,導致經常出現前端加密而後端不能解密的情況出現。然而無論什麼語言系統,AES的演算法總是相同的, 因此導致結果不一致的原因在於 加密設置的參數不一致 。於是先來看看在兩個平台使用AES加密時需要統一的幾個參數。
參考: https://welkinx.com/2016/07/30/10/
ios中使用AES128位 ECB模式加密 結果轉換16進制
https://tieba..com/p/4581819586
與伺服器通訊的時候,除了確定密鑰外,加密模式和填充方式也要確定。第一個例子中,就是使用了kCCOptionPKCS7Padding加密模式,並且有IV(初始向量),而第二個例子中使用了ECB(沒有補碼方式)。
此外也要注意轉碼後的密文是轉成16進制,還是base64編碼。
參考鏈接:
http://blog.51cto.com/ciphertext/1420338
https://welkinx.com/2016/07/30/10/
https://tieba..com/p/4581819586
㈧ IOS 演算法(基礎篇) ----- 兩個數組的交集
例子:
輸入派閉行:nums1 = [1,2,3,4], nums2 = [2,2]
輸出:[2]
輸入:nums1 = [7,9,8], nums2 = [9,4,9,8,4,5,10]
輸出:[9,8]
1.先Set方法去重num1, 減少循環, let set1 = Set(nums1)
(Set和Array的區別在於,Set是無塵嘩序的,且Set中不能存在重態畢復的元素)
2.遍歷set1, 如果num2包含 , result就插入
/// Returns a new set with the elements that are common to both this set and
/// the given sequence.
///
/// In the following example, the bothNeighborsAndEmployees set is made up
/// of the elements that are in both the employees and neighbors sets.
/// Elements that are in only one or the other are left out of the result of
/// the intersection.
///
/// let employees: Set = ["Alicia", "Bethany", "Chris", "Diana", "Eric"]
/// let neighbors: Set = ["Bethany", "Eric", "Forlani", "Greta"]
/// let bothNeighborsAndEmployees = employees.intersection(neighbors)
/// print(bothNeighborsAndEmployees)
/// // Prints "["Bethany", "Eric"]"
㈨ 介紹iOS中MD5加密演算法的使用
前言
軟體開發過程中,對數據進行加密是保證數據安全的重要手段,常見的加密有Base64加密和MD5加密。Base64加密是可逆的,MD5加密目前來說一般是不可逆的。
MD5生成的是固定的128bit,即128個0和1的二進制位,而在實際應用開發中,通常是以16進制輸出的,所以正好就是32位的16進制,說白了也就是32個16進制的數字。
MD5主要特點是 不可逆,相同數據的MD5值肯定一樣,不同數據的MD5值不一樣(也不是絕對的,但基本是不能一樣的)。
MD5演算法還具有以下性質:
1、壓縮性:任意長度的數據,算出的MD5值長度都是固定的。
2、容易計算:從原數據計算出MD5值很容易。
3、抗修改性:對原數據進行任何改動,哪怕只修改1個位元組,所得到的MD5值都有很大區別。
4、弱抗碰撞:已知原數據和其MD5值,想找到一個具有相同MD5值的數據(即偽造數據)是非常困難的。
5、強抗碰撞:想找到兩個不同的數據,使它們具有相同的MD5值,是非常困難的。
6、MD5加密是不可解密的,但是網上有一些解析MD5的,那個相當於一個大型的資料庫,通過匹配MD5去找到原密碼。所以,只要在要加密的字元串前面加上一些字母數字元號或者多次MD5加密,這樣出來的結果一般是解析不出來的。
MD5的應用:
由於MD5加密演算法具有較好的安全性,而且免費,因此該加密演算法被廣泛使用
大多數的'登錄功能向後台提交密碼時都會使用到這種演算法
注意點:
(1)一定要和後台開發人員約定好,MD5加密的位數是16位還是32位(大多數都是32位的),16位的可以通過32位的轉換得到。
(2)MD5加密區分 大小寫,使用時要和後台約定好。
MD5解密:
解密網站:http://www.cmd5.com/
為了讓MD5碼更加安全 涌現了很多其他方法 如加鹽。 鹽要足夠長足夠亂 得到的MD5碼就很難查到。
終端代碼:$ echo -n abc|openssl md5 給字元串abc加密、
蘋果包裝了MD5加密的方法,使用起來十分的方便。
#import@interface MD5Encrypt : NSObject// MD5加密/**由於MD5加密是不可逆的,多用來進行驗證*/// 32位小寫+(NSString *)MD5ForLower32Bate:(NSString *)str;// 32位大寫+(NSString *)MD5ForUpper32Bate:(NSString *)str;// 16為大寫+(NSString *)MD5ForUpper16Bate:(NSString *)str;// 16位小寫+(NSString *)MD5ForLower16Bate:(NSString *)str;@end
#import "MD5Encrypt.h"#import@implementation MD5Encrypt#pragma mark - 32位 小寫+(NSString *)MD5ForLower32Bate:(NSString *)str{ //要進行UTF8的轉碼 const char* input = [str UTF8String]; unsigned char result[CC_MD5_DIGEST_LENGTH]; CC_MD5(input, (CC_LONG)strlen(input), result); NSMutableString *digest = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; for (NSInteger i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { [digest appendFormat:@"%02x", result[i]]; } return digest;}#pragma mark - 32位 大寫+(NSString *)MD5ForUpper32Bate:(NSString *)str{ //要進行UTF8的轉碼 const char* input = [str UTF8String]; unsigned char result[CC_MD5_DIGEST_LENGTH]; CC_MD5(input, (CC_LONG)strlen(input), result); NSMutableString *digest = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; for (NSInteger i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { [digest appendFormat:@"%02X", result[i]]; } return digest;}#pragma mark - 16位 大寫+(NSString *)MD5ForUpper16Bate:(NSString *)str{ NSString *md5Str = [self MD5ForUpper32Bate:str]; NSString *string; for (int i=0; i<24; i++) { string=[md5Str substringWithRange:NSMakeRange(8, 16)]; } return string;}#pragma mark - 16位 小寫+(NSString *)MD5ForLower16Bate:(NSString *)str{ NSString *md5Str = [self MD5ForLower32Bate:str]; NSString *string; for (int i=0; i<24; i++) { string=[md5Str substringWithRange:NSMakeRange(8, 16)]; } return string;}@end
㈩ iOS中的哈希表
哈希表也叫散列表,是根據鍵值(Key value)而直接進行訪問的數據結構。也就是說,它通過把鍵(Key)映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫做哈希函數,映射函數得出的值叫哈希值或哈希碼,存放記錄的數組叫做哈希表。哈希表中存放數據占總空間比例叫做裝填因子(負載因子)。
哈希函數的設計要達到輸出值的平均分布化,這樣能盡可能降低哈希沖突的概率。
一般情況下,哈希函數中輸入值與輸出值具有 N對1 關系。
哈希函數具有的特點:如果兩個哈希碼不同,則它們的鍵(Key)也一定不同。
該特點常用於優化比較兩個對象是否相同,先判斷hash碼是否相同,若hash碼不同則不需要進行對象比較。
哈希表優點:查找效率高,插入刪除和查找時間復雜度為O(1)。
哈希表缺點:佔用空間大,需要預留一定空間,否則哈希沖突概率會很大。哈希表無法記錄插入順序。
哈希函數因為會N對1的關系,會觸發哈希沖突。哈希沖突常見解決方式有有以下幾種:
1. 開放定址法
線性探測(偏移1,2,3..)
可能會導致數據堆積一起,降低插入刪除和查找效率。
二次方探測(偏移1*1,2*2,3*3..)
相比線性探測不容易造成數據堆積,但當裝填因子比較大時,可能會造成一次查詢肢升/插入中,同一位置多次被探測。
2. 拉鏈法
使用數組+鏈表解決哈希沖突問題。
開放定址法缺點:
開放定址法的缺點是在刪除元素時,不能真的刪除,否則會引起查找失敗。需要在刪除元素位置做個標記,代表該索引位置可以插入,但是搜索路過時不能中斷搜索。
另一方面,開放定址法因為在沖突時會佔用其它哈希索引空間,所以擴容時裝填因子不能太大。
哈希表擴容與縮容
當裝填因子過大,會增大哈希沖突概率,需要對哈希表進行擴容,因此哈希表一般使用二級指針實現(iOS底層使用DisguisedPtr<void *>)。擴容時需要對所有數據進行重新映射(重哈希),一般每次空間*2。
當裝填因子太小,且空間佔用比較大,比如:if (裝填因子 < 0.1 && num >1024) {縮容}。
哈希演算法本質是一類安全性較高的哈希函數。Hash演算法還具有一個特點,就是很難找到逆向規律。
哈希演算法常用於密碼安全領域,哈希演算法中輸入值與輸出值具有 N對1 關系,常見的哈希演算法包括MD5,SHA,CRC16,CRC32。
SideTables是個全局變數,是StripedMap(哈希表)類型。
StripedMap重載了[],可通過下標的方式快速存取。
StripedMap事實上不是個常規的哈希表,我認為它可以叫做只讀哈希表。它在創建之初就會以模版類型初始化滿所有存儲空間,且不支持修改和擴容。因此,模版類型傳遞指針是沒有意義的。一般模版都設置為結構體,後續操作針對該結構體改值。
SideTables的哈希Key是對象地址addr,哈希函數是((addr >>4) ^ (addr >>9)) %StripeCount,Value是SideTable結構體。因此,SideTables存儲著對象地址與SideTable的 N-1 關系。這樣可以把對象信息分散到不同SideTable中,提升查找效率。
每個SideTable中存儲一堆對象的弱引用表和引用計數表。
weak_table_t的哈希Key是對象地址,哈希函數如下:
Value是weak_entry_t。weak_table_t可以通過對象指針快速找到對象存儲的weak_entry_t。
weak_table_t可進行擴容與縮容。歷瞎老
當出現哈希沖突時,與weak_table_t配套的函數使用線性探測法查找。
每個weak_table_t中神蠢存儲一堆對象的弱引用表。
weak_entry_t只有當裝載數據超過一定長度才會啟用哈希表存儲功能,out_of_line()返回是否啟用哈希表。weak_entry_t的哈希Key是弱指針地址,value也是弱指針地址。哈希函數與weak_table_t相同。
weak_entry_t可進行擴容,不會進行縮容。
當出現哈希沖突時,與weak_entry_t配套的函數使用線性探測法查找。
每個weak_entry_t存儲指向一個對象的所有弱指針地址(二級指針)。
RefcountMap本質是DenseMap類按照指定模版typedef的類型。
RefcountMap的哈希Key是對象地址,Value是引用計數。
當value為0時,RefcountMap會自動清除這條記錄。
當出現哈希沖突時,RefcountMap使用二次方探測法查找。
每個RefcountMap中存儲一堆對象的引用計數。
sDataLists是存儲所有@synchronized鎖的全局哈希表,key是@synchronized的參數。
PropertyLocks是存儲所有atomic鎖的全局哈希表,key是屬性生成的成員變數地址。
類對象的方法緩存cache_t使用哈希表存儲bucket_t(sel+imp),使用逆序線性探測(Index-1)解決哈希沖突。
cache_t擴容時會將所有方法緩存清空。
static objc::ExplicitInitDenseSet<const char *> namedSelectors;
namedSelectors是個全局變數,存儲所有的方法名SEL,內部結構是哈希表DenseMap。
typedef DenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap> AssociationsHashMap;
AssociationsHashMap是AssociationsManager中存儲所有關聯對象的哈希表,內部結構是DenseMap。
NSObject默認的hash方法是對象地址,即默認沒有做優化。
還有個方法isEqual:方法,NSObject默認實現返回該對象與參數對象指針地址是否相同。
hash方法的本質是該對象的哈希函數,需要子類去實現。hash方法主要有兩個作用,這兩個作用在NSDictionary和NSSet中體現出來。
1. 與isEqual:配合,優化比較
先調用hash方法進行比較,若值相同才調用isEqualTo:進行比較。這依賴於hash的 N-1 關系。
從CF源碼中可以找到CFString的源碼,即可以看到NSString內部重寫的hash方法。
這句話的大意是:這個字元串的大小如果小於等於96,則保證哈希的安全;如果大小大於96,則會大幅度增加哈希沖突的概率。
2. 與哈希表配合,hash方法對應哈希表的哈希函數,但返回值需要經過轉換對應存儲索引(一般通過取余)。此時hash方法的設計就非常重要,應做到輸出哈希碼的平均分散化,否則會導致數據堆疊,增大哈希沖突概率。
常見的NSDictionary和NSSet內部就是哈希表,NSDictionary會使用Key作為哈希表的Key,NSSet使用元素作為Key。它們會對Key對象調用hash方法獲得初步的哈希碼,然後經過轉變成為存儲區域的索引(下標)。
NSDictionary和NSSet因為都使用哈希表存儲,因此存儲元素都是無序的。
NSDictionary和NSSet在插入新元素時具體步驟如下: