二、数组
一、線性表
1、定義
線性表(Linear List):零個或多個數據元素的有限序列。
序列(有序):若元素存在多個,則第一個元素無前驅,最后一個無后繼,其他每個元素都有且只有一個前驅和后繼
2、數學表示
線性表:(a1, a2, a3, ..., ai-1, ai, ai+1, ..., an )
ai-1 是 ai 的直接前驅元素, ai+1 是 ai 的直接后繼元素。線性表元素的個數為n(n≥0)定義為線性表的長度,當 n = 0 時,稱為空表
3、線性表的抽象數據類型
ADT 線性表(List) Data線性表的數據對象集合為{a1, a2, ......, an},每個元素的類型均為DataType。其中,除第一個元素a1外,每一個元素有且只有一個直接前驅元素, 除了最后一個元素an外,每一個元素有且只有一個直接后繼元素。 數據元素之間的關系是一對一的關系。 Operation InitList(*L): 初始化操作,建立一個空的線性表L。 ListEmpty(L): 若線性表為空,返回true,否則返回false。 ClearList(*L): 將線性表清空。 GetElem(L, i, *e): 將線性表L中的第i個位置元素值返回給e。 LocateElem(L, e): 在線性表L中查找與給定值e相等的元素,如果查找成功,返回該元素在表中序號表示成功; ListInsert(*L,i,e): 在L的第i個位置插入新元素e。 ListDelete(*L,i,*e): 刪除L中的第i個元素,并用e返回其值。 ListLength(L): 返回L中的元素個數 endADT二、數組(Array)概述
1、定義
數組是一種線性表數據結構。用一組連續的內存空間來存儲一組具有相同類型的數據
解讀:
- 線性表:eg:數組、隊列、棧、鏈表
- 非線性表:eg:樹、堆、圖等
- 連續內存空間 + 相同類型數據 =》隨機訪問
2、存儲
==》元素存儲的內存地址:
其中, data_type_size 表示數組中每個元素的大小。
==》擴展:二維數組的內存尋址公式
對于 m*n 的數組,a[i][j] ( i < m, j < n )的地址為:
三、數組的相關操作
低效的“插入”和“刪除”
1、插入
(1)傳統過程
將一個數據插入到數組中的第 k 個位置。為了把第 k 個位置騰出來,給新來的數據,需要將第 k~n 這部分的元素都順序地往后挪一位。
==》
最好情況時間復雜度為 O(1)
最壞情況時間復雜度為 O(n)
平均情況時間復雜度為 (1+2+…n)/n=O(n)
(2)特殊場景
情況: 如果數組中存儲的數據并沒有任何規律,數組只是被當作一個存儲數據的集合。
方法: 將第 k 位的數據搬移到數組元素的最后,把新的元素直接放入第 k 個位置。
==》復雜度為 O(1)
目標:將 x 插入第 3 個位置 a, b, c, d, e ==》a,b,x,d,e,c2、刪除
(1)傳統過程
要刪除第 k 個位置的數據,為了內存的連續性,也需要搬移數據。
==》
最好情況時間復雜度為 O(1)
最壞情況時間復雜度為 O(n)
平均情況時間復雜度為 (1+2+…n)/n=O(n)
(2)特殊場景
情況: 不一定非得追求數組中數據的連續性。
方法: 先記錄下已經刪除的數據(只記錄數據被刪除,不執行搬移數據的操作)。當數組沒有更多空間存儲數據時,觸發真正的刪除操作,也就是將多次刪除操作集中在一起執行,從而提高刪除的效率。
==》擴展: JVM 標記清除垃圾回收算法的核心思想
==》很多時候我們并不是要去死記硬背某個數據結構或者算法,而是要學習它背后的思想和處理技巧,這些東西才是最有價值的。
四、數組訪問越界問題
1、示例
int main(int argc, char* argv[]){int i = 0;int arr[3] = {0};for(; i <= 3; i++){arr[i] = 0;printf("hello world\0");}return 0; }結果如下:
發生數組訪問越界==》運行結果并非是打印三行“hello word”,而是四行“hello word”或無限打印“hello world”
2、分析
(1)在 C 語言中,只要不是訪問受限的內存,所有的內存空間都是可以自由訪問的。根據我們前面講的數組尋址公式,a[3] 也會被定位到某塊不屬于數組的內存地址上,而這個地址正好是存儲變量i 的內存地址(下面解釋),那么 a[3]=0 就相當于 i=0,所以就會導致代碼無限循環。
(2)函數體內的局部變量存在棧上,且是連續壓棧。在Linux進程的內存布局中,棧區在高地址空間,從高向低增長。變量i和arr在相鄰地址,且i比arr的地址大,所以arr越界正好訪問到i。當然,前提是i和arr元素同類型,否則那段代碼仍是未決行為。
五、容器 vs. 數組
很多語言都提供了容器類,比如 Java 中的 ArrayList、C++ STL 中的 vector。
容器類的最大的優勢就是可以將很多數組操作的細節封裝起來。
容器適用于業務開發,省時省力;非常底層的開發(網絡框架等)或性能要求特別高,優先使用數組
總結
- 上一篇: Ubuntu下pip3的安装、升级、卸载
- 下一篇: 三、链表(Linked List)(原理