數據結構課程學習筆記。java
數組(Array)是一種線性表數據結構。它用一組連續的內存空間,來存儲一組具備相同類型的數據, 而且不支持動態擴容。git
線性表就是數據排成一條線同樣的數據結構,每一個線性表最多隻有先後兩個方向,數組,鏈表丶隊列丶棧等都是線性表數據結構。github
非線性表就是數據不規則,與線性表是相對立的,好比二叉樹丶堆丶等,在非線性表中,數據之間並非簡單的先後關係。數組
address[i] = base_address + i * data_type_size
複製代碼
address[i] : 下標 i 的地址值。緩存
base_address: 數組的首地址。數據結構
data_type_size: 數組中每一個元素的大小,也就是數據類型大小(字節),例如int是4個字節。oop
數組 (Array) 在增刪查這三個動做中,查詢是高效的,可是增和刪是低效的,查詢高效是由於數組支持隨機訪問,時間複雜度是 O(1) ,這裏就很少贅述了,可是在增長和刪除的動做中,由於會涉及數據搬移,因此時間複雜度是 O(n) ,下面來詳細講解。性能
int[] info = new int[6];
複製代碼
數組 info 是一個一維數組,其內容是 33,44,66,77,88 如今須要在下標 2 的位置插入 55 ,將其變成33 44 55 66 77 88的數組,這其中涉及將下標 2 到下標 4 的之間進行數據進行搬移,完成後在下標 2 的位置插入 55 , 其複雜度是 O(n), 但若是是在最後進行插入的話其複雜度是 O(1)。學習
還拿數組 info 來舉例,數組刪除前其內容是 33,44,00,55,66,77 如今進行刪除操做,刪除下標爲 2 內容,這其中涉及將下標 3 到 5 的內容向前搬移,其操做的時間複雜度是 O(n) ,若是是是刪除最後一位且後面沒有內容,則其時間複雜度是O(1) 。測試
因插入和刪除操做會涉及到數據搬移,因此說他是低效的。
Cpu緩存的最小單位是Cpu緩存行,一個緩存行大小一般是64字節(取決於CPU),試想一下你正在遍歷一個長度爲 16 的 long 數組 data[16],原始數據天然存在於主內存中,訪問過程描述以下:
1:訪問 data[0],CPU core 嘗試訪問 CPU Cache,未命中。
2:嘗試訪問主內存,操做系統一次訪問的單位是一個 Cache Line 的大小 — 64 字節,這意味着:既從主內存中獲取3:到了 data[0] 的值,同時將 data[0] ~ data[7] 加入到了 CPU Cache 之中,
4:訪問 data[1]~data[7],CPU core 嘗試訪問 CPU Cache,命中直接返回。
5:訪問 data[8],CPU core 嘗試訪問 CPU Cache,未命中, 嘗試訪問主存,重複步驟2。
因Cpu緩存最小單位是緩存行(64字節),我麼來測試一下二維數組的橫向遍歷和縱向遍歷的具體時間和性能。
代碼
package com.com.array;
/** * @Auther: lantao * @Date: 2019-06-24 15:52 * @Company: 隨行付支付有限公司 * @maill: lan_tao@suixingpay.com * @Description: TODO */
public class ArrayTest {
static long[][] arr;
public static void main(String[] args) {
long sum = 0L;
arr = new long[1024 * 1024][10];
// 橫向遍歷
long l = System.currentTimeMillis();
for (int i = 0; i < 1024 * 1024; i++) {
for (int j = 0; j < 10; j++) {
sum += arr[i][j];
}
}
System.out.println("Loop Time 橫向遍歷:" + (System.currentTimeMillis() - l) + "ms");
long l1 = System.currentTimeMillis();
// 縱向遍歷
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 1024 * 1024; j++) {
sum += arr[j][i];
}
}
System.out.println("Loop Time 縱向遍歷:" + (System.currentTimeMillis() - l) + "ms");
}
}
複製代碼
結果:
Loop Time 橫向遍歷:14ms
Loop Time 縱向遍歷:83ms
複製代碼
總結: 因橫向遍歷遍歷的是行,而後在循環行的每一列,Cpu緩存會緩存64字節大小的緩存行,因此能夠減小cpu和主存之間的交互,直接和高速緩存交互,提高性能,縱向遍歷因每次循環都是不一樣的行,因此使緩存行沒有做用。