稀疏數組如何幫助我們節省內存,提升性能

本文由葡萄城技術團隊發佈。轉載請註明出處:葡萄城官網,葡萄城爲開發者提供專業的開發工具、解決方案和服務,賦能開發者。

什麼是稀疏矩陣

稀疏矩陣是指矩陣中大部分元素爲零的矩陣。在實際應用中,很多矩陣都是稀疏的,比如網絡圖、文本數據等。由於矩陣中存在大量的零元素,因此稀疏矩陣的存儲和計算都具有一定的特殊性。

一般來說,在矩陣中,若數值爲0的元素數目遠遠多於非0元素的數目,並且非0元素分佈沒有規律時,則稱該矩陣爲稀疏矩陣;與之相反,若非0元素數目佔大多數時,則稱該矩陣爲稠密矩陣。下面的矩陣就是一個典型的稀疏矩陣:

優化稀疏矩陣數據存儲的方法

1.直接存儲爲二維矩陣

使用二維矩陣作爲電子表格的存儲方法具有簡單直接的優點,可以避免頻繁地創建或刪除內存段。然而,需要指出的是,這種方式在存儲值時可能會有一些不太高效的方面,因爲它會佔用大量的存儲空間來保存沒有實際內容的單元格。

在實際應用中通常使用三元組表示稀疏矩陣:

三元組的表示方法是:對於一個 m×n 的稀疏矩陣 A,我們只存儲矩陣中非零元素的信息,具體來說,將每個非零元素的行下標、列下標和值存儲下來,得到一個三元組(i,j,Ai,j),其中 i 是行下標,j 是列下標,Ai,jA 中對應位置的值。

以前面舉的稀疏矩陣爲例,其三元組表示如下:

(1, 4, 6)
(2, 2, 5)
(3, 3, 4)

直接存儲爲二維矩陣的複雜度:

  • 佔用空間:O(N2)
  • 插入數據:需要破壞矩陣。
  • 刪除數據:需要破壞矩陣。
  • 搜索數據:O(N2)。
  • 訪問數據:O(1)。

N是假設行和列具有相同長度並形成正方形矩陣的行/列數。

2.通過鍵值對(Map, Dictionary)優化

通過鍵值對(Map, Dictionary)來優化,主要是利用哈希表的特性來快速查找元素。具體來說,可以將需要查找的元素作爲鍵,將存儲這些元素的數據結構作爲值,然後將它們存儲在一個哈希表中。這樣,當需要查找某個元素時,只需要使用該元素作爲鍵,通過哈希表的查找操作即可快速找到對應的值。

在實際應用中,常見的情況包括:

  1. 緩存數據:在需要頻繁訪問數據的場景中,通過建立一個緩存,將數據存儲在一個鍵值對的數據結構中,可以顯著提高數據的訪問效率。
  2. 字符串處理:在需要對字符串進行匹配、查找等操作的場景中,可以將字符串作爲鍵,將相應的處理結果作爲值,存儲在一個鍵值對的數據結構中,可以大幅提高字符串處理的效率。
  3. 數據庫操作:在需要對數據庫進行訪問的場景中,可以使用鍵值對數據結構來存儲查詢結果,避免重複執行查詢操作,減輕數據庫的負載。

在下圖中,將單元格位置和對應的單元格值以鍵值對的形式進行了存儲。

通過鍵值對(Map, Dictionary)優化稀疏數組的複雜度:

  • 空間:O(N)。
  • 插入:O(1)。
  • 刪除:O(1)。
  • 搜索:O(N)。
  • 訪問:O(1)。

N爲所記錄的條目數。

3.通過數組存儲方式優化

在稀疏矩陣中,我們可以使用三個不同的數組來存儲行索引、列偏移、和其中的值,而不是直接在二維矩陣中存儲值。

存儲的三個數組:

  1. =>單元格中的值。
  2. 行索引=>單元格的行索引。
  3. 列偏移=>這裏每個索引都代表列,並且該數組將行開始的索引值存儲在 Row 數組中。

下圖爲將稀疏數組轉化爲數組的形式:

稀疏矩陣具體的插入,刪除,搜索,訪問的代碼:

import java.util.HashMap;
import java.util.Map;

class SparseMatrix {
    private int rows;
    private int cols;
    private Map<String, Integer> matrix;

    public SparseMatrix(int rows, int cols) {
        this.rows = rows;
        this.cols = cols;
        this.matrix = new HashMap<>();
    }

    public void insert(int row, int col, int value) {
        if (row < 0 || row >= rows || col < 0 || col >= cols) {
            throw new IndexOutOfBoundsException("Invalid matrix index");
        }
        if (value != 0) {
            String key = row + "," + col;
            matrix.put(key, value);
        }
    }

    public void delete(int row, int col) {
        String key = row + "," + col;
        matrix.remove(key);
    }

    public int search(int row, int col) {
        String key = row + "," + col;
        return matrix.getOrDefault(key, 0);
    }

    public int access(int row, int col) {
        if (row < 0 || row >= rows || col < 0 || col >= cols) {
            throw new IndexOutOfBoundsException("Invalid matrix index");
        }
        String key = row + "," + col;
        return matrix.getOrDefault(key, 0);
    }
}

在上述代碼中,定義了一個 SparseMatrix 類來表示稀疏矩陣。在構造函數中,我們傳入矩陣的行數和列數,並創建了一個 HashMap 對象 matrix 來存儲非零元素。insert 方法用於向矩陣中插入元素,如果插入的值不爲零,則將其加入 matrix 中,其中鍵爲字符串形式的 row,col。delete 方法用於刪除指定位置的元素,通過 remove 方法從 matrix 中移除對應的鍵值對。search 方法用於搜索指定位置的元素,通過調用 getOrDefault 方法從 matrix 中獲取對應的值,如果不存在則返回默認值 0。access 方法用於訪問指定位置的元素,如果超出矩陣邊界則拋出異常,通過調用 getOrDefault 方法從 matrix 中獲取對應的值。

通過稀疏矩陣存儲方式優化的複雜度:

  • 空間:O(N)。
  • 插入:O(N)。
  • 刪除:O(N)。
  • 搜索:O(N)。
  • 訪問:O(1)。

總結

相較於傳統的數組存儲或鍵值對存儲,稀疏矩陣存儲採用一種基於行索引的數據字典存儲方法,這種方法在處理鬆散佈局的表格數據時表現出色。與其他存儲方式不同,稀疏矩陣只存儲非空數據,無需額外開闢內存空間來存儲空數據。這種特殊存儲策略使得數據片段化變得容易,可以隨時框取整個數據層中的一片數據進行序列化或反序列化。如果在項目開發中需要存儲類似結構的數據,使用稀疏矩陣存儲方式能夠顯著提升性能,無論從時間還是空間上都有很大的優勢,葡萄城公司的純前端表格控件——SpreadJS正是藉助此功能實現了高性能渲染能力(100 毫秒內加載 10 萬行數據)。

擴展鏈接:

Redis從入門到實踐

一節課帶你搞懂數據庫事務!

Chrome開發者工具使用教程

從表單驅動到模型驅動,解讀低代碼開發平臺的發展趨勢

低代碼開發平臺是什麼?

基於分支的版本管理,幫助低代碼從項目交付走向定製化產品開發

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章