數組原理

數據結構課程學習筆記。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緩存的最小單位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緩存行

    因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和主存之間的交互直接和高速緩存交互,提高性能,縱向遍歷因每次循環都是不一樣的行,因此使緩存行沒有做用。

相關文章
相關標籤/搜索