日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[iOS开发]iOS中的Hash

發布時間:2023/12/8 编程问答 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [iOS开发]iOS中的Hash 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 前言
    • 關聯對象的底層原理
    • weak的實現原理
    • KVO的實現原理
    • iOS App簽名的原理
    • 對象引用計數存儲的位置
    • Runloop與線程的存儲關系
    • NSDictionary的原理
  • 哈希表
    • 哈希表定義
    • 哈希表優缺點
    • 哈希查找步驟
    • 哈希表的存儲過程
    • 哈希表的實現
    • 負載因子 = 總鍵值對數/數組的個數
    • 哈希沖突的解決方法
      • 開散列
      • 閉散列
      • 再哈希法
      • 建立公共溢出區
      • 開閉散列二者的比較
        • 拉鏈法的優點:
        • 拉鏈法的缺點:
        • 線性探測法的缺點
  • NSDictionary

前言

天天聽安卓的同學整Hash,猛的發現iOS也有很多底層原理也是Hash來實現的,好好學一下。

iOS中也用到了很多Hash表。

關聯對象的底層原理

[iOS開發]Category、Extension和關聯對象

關聯對象采用的是HashMap嵌套HashMap的結構存儲數據的,簡單來說就是根據對象從第一個HashMap中取出存儲所有關聯對象的第二個HashMap,然后根據屬性名從第二個HashMap中取出屬性對應的值和策略。

問題:為什么關聯對象沒有weak屬性?

weak的實現原理

weak底層原理

weak采用的是一個全局的HashMap嵌套數組的結構存儲數據的。銷毀對象(weak指針指向的對象)的時候,根據對象從HashMap中找到存放所有指向該對象的weak指針的數組,然后將數組中的所有元素(weak指針)都置為nil

weak最大的特點就是在對象銷毀的時候,自動置nil,減少訪問野指針的風險,這也是設計weak的初衷。weak指針置nil的基本步驟:

  • 對象dealloc的時候,從全局的HashMap中,根據一個唯一代碼對象的值作為key,找到存儲所有指向該對象的weak指針的數組
  • 將數組中的所有元素都置nil

蘋果對于weak的實現其實類似于通知的實現,指明誰(weak指針)要監聽誰(賦值對象)什么事件(dealloc操作)執行什么操作(置nil)

KVO的實現原理

GNUstep KVC/KVO探索(二):KVO的內部實現

iOS App簽名的原理

一致性Hash算法 + 非對稱加密算法

iOS App 簽名的原理

對象引用計數存儲的位置

if 對象支持TaggedPointer {return 直接將對象的指針值作為引用計數返回 } else if 設備是64位環境 && Objective-C2.0 {return 對象isa指針的一部分空間(bits_extra_rc) } else {return hash表 }

Runloop與線程的存儲關系

線程和Runloop之間是一一對應的關系,其關系是保存在一個全局的Dictionary里。

線程在剛創建是沒有RunLoop,如果我們不主動獲取,那他就一直都不會有。RunLoop的創建是發生在第一次獲取時,RunLoop的銷毀時發生在線程結束時。我們只能在一個線程內部獲取其RunLoop。

NSDictionary的原理

學完Hash之后我們來學習具體的實現

哈希表

前面說了那么多的底層原理都與Hash表有關,我們來詳細學一下哈希表

哈希表定義

哈希表(hash tabl,也叫散列表),是根據鍵(key)直接訪問在內存存儲位置的數據結構。哈希表本質是一個數組,數組中的每一個元素成為一個箱子,箱子中存放的是鍵值對。根據下標index從數組中取value。關鍵是如何獲取index,這就需要一個固定的函數(哈希函數),將key轉換成index。不論哈希函數設計的如何完美,都可能出現不同的key經過hash處理后得到相同的hash值,這時候我們就需要處理哈希沖突。

哈希表優缺點

優點:把數據的存儲和查找消耗的時間大大降低,幾乎可以看成是常數時間;而代價僅僅是消耗比較多的內存。然而在當前可利用內存越來越多的情況下,用空間換時間的做法是值得的。另外,編碼比較容易也是它的特點之一。

缺點:哈希表通常是基于數組,數組創建后難于擴展。也沒有一種簡便的方法可以以任何一種順序來遍歷哈希表。

所以,如果不需要有序遍歷數據,并且可以提前預測數據量的大小,那么哈希表在速度和易用性方面是無與倫比的。

哈希查找步驟

  • 使用哈希函數將被查找的鍵轉換為數組的索引,理想情況下(hash函數設計合理)不同的鍵映射的數組下標也不同,所有的查找時間復雜度為O(1)。但是實際情況下不是這樣的,所以哈希查找的第二部就是處理哈希沖突。
  • 處理哈希沖突有很多方法,比如拉鏈法、線性探測法…
  • 哈希表的存儲過程

  • 使用hash函數根據key得到哈希值h
  • 如果箱子的個數為n,那么值應該存放在底(h%n)個箱子中。h%n的值范圍為[0,n-1]。
  • 如果該箱子非空(已經存放了一個值)即不同的key得到了相同的h產生了哈希沖突,此時需要使用拉鏈法或者開放定址線性探測法解決沖突
  • 哈希表的實現

    哈希表的底層實際上是基于數組來存儲的,當插入鍵值對時,并不是直接插入該數組中,而是通過對鍵進行Hash運算得到Hash值,然后和數組容量取模,得到在數組中的位置后再插入。取值時,先對指定的鍵求Hash值,再和容量取模得到底層數組中對應的位置,如果指定的鍵值與存貯的鍵相匹配,則返回該鍵值對,如果不匹配,則表示哈希表中沒有對應的鍵值對。這樣做的好處是在查找、插入、刪除等操作可以做到 O ( 1 ) O(1) O(1),最壞的情況是 O ( n ) O(n) O(n),當然這種是最極端的情況,極少遇到。

    負載因子 = 總鍵值對數/數組的個數

    負載因子是哈希表的一個重要屬性,用來衡量哈希表的空/滿成都,一定程度也可以體現查詢的效率。負載因子越大,意味著哈希表越滿,越容易導致沖突,性能也就越低。所以當負載因子大于某個常數(一般是0.75)時,哈希表將自動擴容。哈希表擴容是,一般會創建兩倍于原來的數組長度。這個過程被稱為重哈希(rehash)。

    哈希表擴容在數組比較多的時候需要重新哈希并移動數據,性能影響較大。

    哈希表擴容雖然能夠使負載因子降低,但并不總能有效提高哈希表的查詢性能。比如哈希函數設計的不合理,導致所有的key計算出的哈希值都相同,那么即使擴容他們的位置還是在同一條鏈表上,變成了線性表,性能也極低,查詢時候的時間復雜度就變成了O(n)。

    哈希沖突的解決方法

    大類分為四種 開散列、閉散列、再哈希法、建立公共溢出區

    開散列

    開散列也叫鏈地址法,也叫拉鏈法、哈希桶。

    簡單來說就是 數組 + 鏈表。將鍵通過hash函數映射為大小為M的數組的下標索引,數組的每一個元素指向一個鏈表,鏈表中的每一個節點都存儲著hash出來的索引值為結點下標的鍵值對。

    JAVA 8解決哈希沖突采用的就是拉鏈法。在處理哈希函數設計不合理導致鏈表很長時(鏈表長度超過8切換為紅黑樹,小于6重新退化為鏈表)。將鏈表切換為紅黑樹能夠保證插入和查找的效率,缺點是當哈希表比較大時,哈希表擴容會導致瞬時效率降低。

    Redis解決哈希沖突采用的也是拉鏈法。通過增量式擴容解決了java 8中的瞬時擴容導致的瞬時效率降低的缺點,同時拉鏈法的實現方式(新插入的鍵值對放在鏈表頭部)帶來了兩個好處:
    一、 頭插法可以節省插入耗時。如果插到尾部,則需要時間復雜度為O(n)的操作找到鏈表的尾部,或者需要額外的內存地址來保存尾部鏈表的位置。
    二、頭插法可以節省查找耗時。最新插入的數據往往可能頻繁的被查詢。

    閉散列

    閉散列也叫開放地址法、線性探測法。

    當發生哈希沖突時,且哈希表未滿,可以通過探測的方法吧key存放在沖突位置的下一個位置中。

    方法一:線性探測
    從發生沖突的位置開始,一次向后探測,直到尋找到下一個空位置為止。當然這種方法比較簡單,也有很大的缺陷,就是容易造成數據的堆積,使得關鍵字需要多次比較,這樣以來就導致搜索效率低

    方法二:二次探測

    方法三:偽隨機探測
    建立一個偽隨機數發生器(如 i = (i + p) % m),生成一個偽隨機序列,并給定一個隨機數做起點,每次加上這個偽隨機數,++就可以了。

    再哈希法

    再哈希法其實很簡單,就是再使用哈希函數去散列一個輸入的時候,輸出是同一個位置就再次哈希,直至不發生沖突位置

    缺點:每次沖突都要重新哈希,計算時間增加。

    建立公共溢出區

    這種方法的基本思想是:將哈希表分為基本表和溢出表兩部分,凡是和基本表發生沖突的元素,一律填入溢出表。

    開閉散列二者的比較

    拉鏈法的優點:

    與線性探測法相比,拉鏈法有如下幾個優點:

    • 處理沖突簡單,且無堆積現象,即非同義詞絕不會發生沖突,因此平均查找長度較短;
    • 由于拉鏈法中各鏈表上的結點空間是動態申請的,所以更適合于造表錢無法確定表長的情況
    • 線性探測法為減少沖突,要求裝填因子較小,故當結點規模較大時會浪費很多空間。二拉鏈法中可取a>=1,且結點較大時,拉鏈法中增加的指針域可忽略不計,因此節省空間
    • 在用拉鏈法構造的散列表中,刪除結點的操作易于實現。只要簡單地刪去鏈表上相應的結點即可。而對開放定址線性探測發構造的散列表,刪除結點不能簡單地將被刪結 點的空間置為空,否則將截斷在它之后填人散列表的同義詞結點的查找路徑。這是因為各種開放定址線性探測發中,空地址單元(即開放地址)都是查找失敗的條件。因此在用開放定址線性探測發處理沖突的散列表上執行刪除操作,只能在被刪結點上做刪除標記,而不能真正刪除結點。

    拉鏈法的缺點:

    指針需要額外的空間,故當結點規模較小時,開放定址線性探測法較為節省空間,而若將節省的指針空間用來擴大散列表的規模,可使裝填因子變小,這又減少了開放定址線性探測法中的沖突,從而提高平均查找速度。

    線性探測法的缺點

  • 容易產生堆積問題
  • 不適于大規模的數據存儲
  • 散列函數的設計對沖突會有很大的影響
  • 插入時可能會出現多次沖突的現象,刪除的元素是多個沖突元素中的一個,需要對后面的元素作處理,實現較復雜
  • 結點規模很大時會浪費很多空間
  • NSDictionary

    總結

    以上是生活随笔為你收集整理的[iOS开发]iOS中的Hash的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 操天天 | 久久人人爽人人人人片 | 中文在线√天堂 | 久久影视中文字幕 | 中文字幕精品三级久久久 | 欧美黄色性生活 | 欧美一区二区三区系列电影 | 德国经典free性复古xxxx | 免费精品视频在线观看 | 久久久精品视 | 啪啪免费视频网站 | 老师上课夹震蛋高潮了 | yjizz国产| 欧美性大交 | 免费的黄色的网站 | 国产精品色婷婷 | 成人福利视频在线 | 国产另类视频 | av免费在线观看网站 | 天天综合网在线观看 | 久久免费少妇高潮99精品 | 久久久久久伦理 | 黄色的网站免费观看 | 黄色片网站大全 | 四季av在线一区二区三区 | 日韩色网站 | 精品人妻一区二区三区免费看 | 久久亚洲一区二区三区四区 | 免费a级片在线观看 | 在线1区 | 91看片网页版 | 日批黄色片 | 日本不卡在线观看 | 在线视频福利 | 天天噜夜夜噜 | 日韩av影片 | 成熟丰满熟妇高潮xxxxx视频 | 国产视频在线看 | 日本成人一区二区三区 | 99国产精品99久久久久久粉嫩 | 亚洲av永久中文无码精品综合 | 九一亚洲精品 | 亚洲一区二区三区四区五区午夜 | 国产极品福利 | 91精品成人 | 美日韩精品视频 | 精品视频不卡 | 欧美亚洲日本在线 | 国内自拍小视频 | 免费在线观看污网站 | www国产亚洲精品久久麻豆 | 床戏高潮做进去大尺度视频网站 | 一区二区国产精品视频 | 在线观看视频日韩 | 日韩激情久久 | 亚洲日本视频在线观看 | 精品视频一区二区三区在线观看 | 久久97精品久久久久久久不卡 | 成人av免费看 | 一区二区三区人妻 | 体内射精一区二区 | 国产成人无码一区二区在线播放 | 国产精品一区二区久久国产 | 奇米影视播放器 | 四虎成人精品在永久免费 | 九九在线免费视频 | 欧美日韩一区二区久久 | 超碰伊人久久 | 超碰在线99| 射射色 | 日韩在线一级 | 自拍偷拍国产精品 | 激情六月天 | 伊人久久久久噜噜噜亚洲熟女综合 | 婷婷丁香在线 | 91av视频网 | a级在线观看视频 | 日韩少妇毛片 | 在线毛片网 | 麻豆视频网站在线观看 | 国产免费网址 | 中文幕无线码中文字蜜桃 | 黄色在线免费看 | 欧美精品自拍视频 | a级片中文字幕 | 男女插插网站 | 国产午夜视频在线 | 永久黄网站| 一区二区三区免费看视频 | 亚洲熟女乱色一区二区三区 | 成人午夜视频在线播放 | 精品三级在线 | 澳门黄色一级片 | 神马久久久久久久久久 | 少妇特黄一区二区三区 | 欧美午夜性春猛交 | 高清在线一区二区 | 黄色国产在线观看 | 国产精品一卡二卡 |