數(shù)據(jù)結構的分類
數(shù)據(jù)結構是指相互之間存在著一種或多種關系的數(shù)據(jù)元素的集合和該集合中數(shù)據(jù)元素之間的關系組成
簡單來說:數(shù)據(jù)結構是以某種特定的布局方式存儲數(shù)據(jù)的容器。這種“布局方式”決定了數(shù)據(jù)結構對于某些操作是高效的,而對于其他操作則是低效的。首先我們需要理解各種數(shù)據(jù)結構,才能在處理實際問題時選取最合適的數(shù)據(jù)結構。
常用的數(shù)據(jù)結構有:數(shù)組,棧,鏈表,隊列,樹,圖,堆,散列表等
1、數(shù)組
數(shù)組是可以再內(nèi)存中連續(xù)存儲多個元素的結構,在內(nèi)存中的分配也是連續(xù)的,數(shù)組中的元素通過數(shù)組下標進行訪問,數(shù)組下標從0開始
NSArray *array = [NSArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
// NSArray *array = @[@"1",@"2",@"3",@"4"];
NSLog(@"%@",array[0]);
優(yōu)點:
- 1、按照索引查詢元素速度快
- 2、按照索引遍歷數(shù)組方便
缺點:
- 1、數(shù)組的大小固定后就無法擴容了
- 2、數(shù)組只能存儲一種類型的數(shù)據(jù)
- 3、添加,刪除的操作慢,因為要移動其他的元素。
適用場景:
- 頻繁查詢,對存儲空間要求不大,很少增加和刪除的情況。
2、棧
棧是一種特殊的線性表
,僅能在線性表的一端操作,棧頂允許操作,棧底不允許操作。棧的特點是:先進后出,或者說是后進先出,從棧頂放入元素的操作叫入棧,取出元素叫出棧
線性表是最基本、最簡單、也是最常用的一種數(shù)據(jù)結構。線性表(linear list)是數(shù)據(jù)結構的一種,一個線性表是n個具有相同特性的數(shù)據(jù)元素的有限序列。
線性表中數(shù)據(jù)元素之間的關系是一對一的關系,即除了第一個和最后一個數(shù)據(jù)元素之外,其它數(shù)據(jù)元素都是首尾相接的(注意,這句話只適用大部分線性表,而不是全部。比如,循環(huán)鏈表邏輯層次上也是一種線性表(存儲層次上屬于鏈式存儲),但是把最后一個數(shù)據(jù)元素的尾指針指向了首位結點)
3、隊列
隊列與棧一樣,也是一種線性表,不同的是,隊列可以在一端添加元素,在另一端取出元素,也就是:先進先出。從一端放入元素的操作稱為入隊,取出元素為出隊
4、鏈表
鏈表是一種物理存儲單元上非連續(xù)、非順序的存儲結構,數(shù)據(jù)元素的邏輯順序是通過鏈表中的指針鏈接次序實現(xiàn)的。鏈表由一系列結點(鏈表中每一個元素稱為結點)組成,結點可以在運行時動態(tài)生成。每個結點包括兩個部分:一個是存儲數(shù)據(jù)元素的數(shù)據(jù)域,另一個是存儲下一個結點地址的指針域。 相比于線性表順序結構,操作復雜。由于不必須按順序存儲,鏈表在插入的時候可以達到O(1)
的復雜度,比另一種線性表順序表快得多,但是查找一個節(jié)點或者訪問特定編號的節(jié)點則需要O(n)
的時間,而線性表和順序表相應的時間復雜度分別是O(logn)和O(1)。
根據(jù)指針的指向,鏈表能形成不同的結構,例如單鏈表
,雙向鏈表
,循環(huán)鏈表
等。
雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個數(shù)據(jù)結點中都有兩個指針,分別指向直接后繼和直接前驅。所以,從雙向鏈表中的任意一個結點開始,都可以很方便地訪問它的前驅結點和后繼結點。一般我們都構造雙向循環(huán)鏈表。
鏈表的優(yōu)點:
- 鏈表是很常用的一種數(shù)據(jù)結構,不需要初始化容量,可以任意加減元素;
- 添加或者刪除元素時只需要改變前后兩個元素結點的指針域指向地址即可,所以添加,刪除很快;
缺點:
- 因為含有大量的指針域,占用空間較大;
- 查找元素需要遍歷鏈表來查找,非常耗時。
適用場景:
- 數(shù)據(jù)量較小,需要頻繁增加,刪除操作的場景
5、樹
樹是一種數(shù)據(jù)結構,它是由n(n>=1)
個有限節(jié)點組成一個具有層次關系的集合。把它叫做 “樹” 是因為它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的。它具有以下的特點:
- 每個節(jié)點有零個或多個子節(jié)點;
- 沒有父節(jié)點的節(jié)點稱為根節(jié)點;
- 每一個非根節(jié)點有且只有一個父節(jié)點;
- 除了根節(jié)點外,每個子節(jié)點可以分為多個不相交的子樹;
在日常的應用中,我們討論和用的更多的是樹的其中一種結構,就是二叉樹
。
二叉樹是樹的特殊一種,具有如下特點:
- 1、每個結點最多有兩顆子樹,結點的度最大為2。
- 2、左子樹和右子樹是有順序的,次序不能顛倒。
- 3、即使某結點只有一個子樹,也要區(qū)分左右子樹。
二叉樹是一種比較有用的折中方案,它添加,刪除元素都很快,并且在查找方面也有很多的算法優(yōu)化,所以,二叉樹既有鏈表的好處,也有數(shù)組的好處,是兩者的優(yōu)化方案,在處理大批量的動態(tài)數(shù)據(jù)方面非常有用。
二叉樹有很多擴展的數(shù)據(jù)結構,包括
平衡二叉樹
、紅黑樹
、B+樹
等,這些數(shù)據(jù)結構二叉樹的基礎上衍生了很多的功能,在實際應用中廣泛用到,例如mysql
的數(shù)據(jù)庫索引結構用的就是B+樹
,還有HashMap
的底層源碼中用到了紅黑樹
。這些二叉樹的功能強大,但算法上比較復雜,想學習的話還是需要花時間去深入的。
6、散列表
散列表,也叫哈希表
,是根據(jù)關鍵碼
和值 (key和value)
直接進行訪問的數(shù)據(jù)結構,通過key
和value
來映射到集合中的一個位置,這樣就可以很快找到集合中的對應元素。
記錄的存儲位置=f(key)
- 這里的對應關系
f
成為散列函數(shù)
,又稱為哈希 (hash函數(shù))
,而散列表就是把Key
通過一個固定的算法函數(shù)
既所謂的哈希函數(shù)
轉換成一個整型數(shù)字
, - 然后就將該數(shù)字對數(shù)組長度進行
取余
,取余結果就當作數(shù)組的下標
- 將value存儲在以該數(shù)字為下標的
數(shù)組空間里
- 這種存儲空間可以充分利用數(shù)組的查找優(yōu)勢來查找元素,所以查找的速度很快。
哈希表在應用中也是比較常見的,就如Java
中有些集合類就是借鑒了哈希原理構造的,例如HashMap
,HashTable
等,利用hash表的優(yōu)勢,對于集合的查找元素時非常方便的,然而,因為哈希表是基于數(shù)組衍生的數(shù)據(jù)結構
,在添加刪除元素方面是比較慢的,所以很多時候需要用到一種數(shù)組鏈表來做,也就是拉鏈法
。拉鏈法是數(shù)組結合鏈表的一種結構
,較早前的hashMap底層的存儲就是采用這種結構,直到jdk1.8之后才換成了數(shù)組加紅黑樹的結構.iOS
中weak表(弱引用表)
就是典型的哈希表
- 左邊很明顯是個數(shù)組,數(shù)組的每個成員包括一個指針,指向一個鏈表的頭,
- 當然這個鏈表可能為空,也可能元素很多。
- 我們根據(jù)元素的一些特征把元素分配到不同的鏈表中去,
- 也是根據(jù)這些特征,找到正確的鏈表,再從鏈表中找出這個元素。
哈希表的應用場景很多,當然也有很多問題要考慮,比如哈希沖突的問題,如果處理的不好會浪費大量的時間,導致應用崩潰。
7、堆
堆是一種比較特殊的數(shù)據(jù)結構,可以被看做一棵樹的數(shù)組對象
,具有以下的性質:
- 堆中某個節(jié)點的值總是不大于或不小于其父節(jié)點的值;
- 堆總是一棵完全二叉樹。
將根節(jié)點最大的堆叫做最大堆或大根堆
,根節(jié)點最小的堆叫做最小堆或小根堆
。常見的堆有二叉堆
、斐波那契堆
等。
堆的定義如下:n個元素的序列{k1,k2,ki,…,kn}當且僅當滿足下關系時,稱之為堆。
(ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4…n/2),
滿足前者的表達式的成為小頂堆
,滿足后者表達式的為大頂堆
,這兩者的結構圖可以用完全二叉樹排列出來
8、圖
圖型結構也稱圖案
,指個體目標重復排列的空間形式。圖案反映了地物的空間分布特征,它可以是自然的,也可以是人為構造的。 [1] 圖形結構,簡稱“圖”,是一種復雜的數(shù)據(jù)結構。圖形結構中,每個結點的前驅結點數(shù)和后續(xù)結點數(shù)可以任意多個。
數(shù)據(jù)元素間的關系是任意的。其他數(shù)據(jù)結構(如樹、線性表等)都有明確的條件限制,而圖形結構中任意兩個數(shù)據(jù)元素間均可相關聯(lián)。常用來研究生產(chǎn)流程、施工計劃、各種網(wǎng)絡建設等問題。