1. 程式人生 > >python資料結構學習筆記-2016-10-22-03-稀疏矩陣

python資料結構學習筆記-2016-10-22-03-稀疏矩陣

        4.5 應用:稀疏矩陣

        稀疏矩陣(Sparse Matrix):一個矩陣中大部分元素都是零元素的矩陣(m × n),即其非零元素個數k << m × n。

        與稀疏矩陣相反的是稠密矩陣。

        如果採用二維陣列來實現稀疏矩陣,就意味著大部分的記憶體都會用來儲存零元素,這就會造成記憶體的極大浪費,相關操作也會變得低效(?)。

        基於此,本節來考慮使用python列表來實現稀疏矩陣。稀疏矩陣中的每一個非零元素都以儲存類例項存在,其屬性包括所在行、所在列以及相應值,而python列表的每一項就是指向儲存類例項的引用。


        4.1.2 基於列表的實現

#-*-coding: utf-8-*-

# 使用列表實現稀疏矩陣

class SparseMatrix(object):
    def __init__(self, numRows, numCols):
        self._numRows = numRows
        self._numCols = numCols
        self._elementList = list()

    def numRows(self):
        return self._numRows

    def numCols(self):
        return self._numCols

    def __getitem__(self, ndxTuple):
        ndx = self._findPosition(ndxTuple[0], ndxTuple[1])
        if ndx is not None:
            return self._elementList[ndx].value
        else:
            return 0

    def __setitem__(self, ndxTuple, scalar):
        ndx = self._findPosition(ndxTuple[0], ndxTuple[1])
        if ndx is not None: # 當指定索引是非零元素時
            if scalar != 0.0: # 新傳入的值不是0,直接賦值
                self._elementList[ndx].value = scalar
            else: # 新傳入的值為0時,只需從列表中刪除這一項,即表明指定索引的值是0
                self._elementList.pop(ndx)
        else: # 當指定索引是0時
            if scalar != 0.0 # 傳入值非零,即在底層列表中新增一項即可
                element = _MatrixElement(ndxTuple[0], ndxTuple[1], scalar)
                self._elementList.append(element)

    # 數乘運算
    def scaleBy(self, scalar):
        for element in self._elementList:
            element.value *= scalar

    # 矩陣加法
    def __add__(self, other):
        assert other.numRows() == self.numRows() and other.numCols() == self.numCols(), "Matrix sizes not compatible for the add operation."
        newMatrix = SparseMatrix(self.numRows(), self.numCols())
        # 將self中的所有非零項複製到newMatrix中
        for element in self._elementList:
            dupElement = _MatrixElement(element.row, element.col, element.value)
            newMatrix._elementList.append(dupElement)
        # 將other中的所有非零項加到newMatrix中
        for element in other._elementList:
            newMatrix[element.row, element.col] += element.value
        return newMatrix

    # 矩陣減法
    def __sub__(self, other):
        pass

    # 矩陣乘法
    def __mul__(self, other):
        pass

    # 輔助方法
    def _findPosition(self, row, col):
        n = len(self._elementList)
        for i in range(n):
            if row == self._elementList[i].row and col == self._elementList[i].col:
                return i
        return None

# 儲存類,儲存非零元素的值,以及其在矩陣中的位置
class _MatrixElement(object):
    def __init__(self, row, col, value):
        self.row = row
        self.col = col
        self.value = value
        輔助方法_findPosition(),是將稀疏矩陣索引與列表索引一一對應起來。由於列表儲存的例項物件中,已包含該非零項所在索引,所以稀疏矩陣的所有非零元素在列表中並不是按照特定順序排列的。

        值得注意的是,在修改稀疏矩陣的值時,會出現以下四種情況:

  • 原值非零,新值非零;
  • 原值非零,新值是零;
  • 原值是零,新值非零;
  • 原值是零,新值是零。
        這四種情況在程式中得到了分別處理。

        還要值得注意的是稀疏矩陣的加法運算,程式中首先是建立新的係數矩陣,再將原有的稀疏矩陣所有非零項複製到新的稀疏矩陣中,再將另一個稀疏矩陣中的非零項加進來,最後一步依賴於__gettitem__()和__setitem__()的準確實現。

        4.5.2 效率分析

操作 矩陣 稀疏矩陣
構造器 O(n²) O(1)
s.numRows() O(1) O(1)
s.numCols() O(1) O(1)
s.scaleBy(x) O(n²) O(k)
x = s[i, j] O(1) O(k)
s[i, j] = x O(1) O(k)
r = s + t O(n²) O(k²)

       假設矩陣是n × n,稀疏矩陣含有k個非零元素,_findPosition()的執行時間是O(k)。__gettitem__()和__setitem__()都呼叫了_findPosition(),所以執行時間都是O(k),比起矩陣來說要慢。

       但是在構造器方面,矩陣是O(n²),因為呼叫了clear(),而clear()中含有一個巢狀迴圈,而稀疏矩陣只是構造了一個空列表。

       數乘運算方面,矩陣是每一個元素都乘以相應的數值,需要遍歷每一個元素,所以是O(n²),而稀疏矩陣只需將列表中每一個值乘以給定的數值即可,因此是O(k)。

       在加法上,矩陣需要遍歷每一個元素,並與對應元素相加,時間是O(n²),而在稀疏矩陣中,複製所有項需要O(k),在第二個迴圈中,要注意newMatrix[element.row, element.col]本身就需要O(k),這一操作又要迴圈k次,所以時間是O(k) + O(k²) = O(k²)。兩者效率的高低要取決於k。


相關推薦

python資料結構學習筆記-2016-10-22-03-稀疏矩陣

        4.5 應用:稀疏矩陣         稀疏矩陣(Sparse Matrix):一個矩陣中大部分元素都是零元素的矩陣(m × n),即其非零元素個數k << m × n。         與稀疏矩陣相反的是稠密矩陣。         如果採用二維

python資料結構學習筆記-2017-01-08-01-N皇后問題、迷宮問題和跳馬問題的遞迴解決

        N皇后問題         棋盤ADT #-*-coding: utf-8-*- # 二維陣列實現棋盤ADT from myarray2d import Array2D class Board(object): def __init__(se

資料結構學習筆記之線性表

一、概念 什麼是線性表呢? 一個簡單的理解如下: 線性表是由稱為元素(Element)的資料項組成的一種有限且有序的序列 其中,這裡有一個需要注意的地方: 有序是指線性表中的每個元素都有自己的位置,而不是指線性表中的元素按某種順序排列 二、抽象資料型別定義 要給資料結構定

資料結構學習筆記------紅黑樹(附c++程式碼)

1、紅黑樹簡介 紅黑樹是二叉查詢樹的一種,其增刪改查的統計效能要優於AVL樹,查詢、插入、刪除演算法的複雜度都為O(log(n))。先附上紅黑樹這種資料結構的性質: 性質1、節點是紅色或黑色。 性質2、根節點是黑色。 性質3、每個葉節點(是指的空節點,nil節點)是黑色的。 性質4、

資料結構學習筆記------並查集(附cf例題)

並查集是將原始的資料集S看成一個森林,每棵樹代表一個集合。初始時,每個資料看成一顆只有根節點的樹,根據具體要求,將若干樹合併起來組成若干個含有節點較多的樹,每棵樹就是一個集合。此資料結構可以方便的對資料集S進行:(1)查詢其屬於哪個集合(2)將一個集合合併到另一個集合的操作。要注意的是,

python資料結構與演算法(10

棧棧(stack),有些地⽅稱為堆疊,是⼀種容器,可存⼊資料元素、訪問元 素、刪除元素,它的特點在於只能允許在容器的⼀端(稱為棧頂端指標,英 語:top)進⾏加⼊資料(英語:push)和輸出資料(英語:pop)的運算。 沒有了位置概念,保證任何時候可以訪問、刪除的元素都是此前最後存⼊的 那個元素,確定了⼀種預

資料結構學習筆記】二叉樹和其他樹

基礎定義 一個樹t是一個非空的有限元素的集合,其中一個元素為根(root),其餘的元素(如果有的話)組成t的子樹(subtree) 樹的另一常用術語為級(level)。樹根是1級,其孩子(如果有)是2級,孩子的孩子是3級,等等。 一棵樹的高度(height)或深度(de

資料結構學習筆記之列表

#include <iostream> using namespace std; typedef int Rank; #define Posi(T) ListNode<T>* //列表節點位置 //節點叫法:頭 首 末 尾 template<ty

Python資料爬蟲學習筆記(13)爬取微信文章資料

一、需求:在微信搜尋網站中,通過設定搜尋關鍵詞以及搜尋頁面數,爬取出所有符合條件的微信文章: 二、搜尋頁URL分析階段: 1、在搜尋框中輸入任意關鍵詞,在出現的搜尋結果頁面點選下一頁,將每一頁的URL複製下來進行觀察: 2、注意到頁碼由page=X決定,搜尋關鍵

Python資料爬蟲學習筆記(15)Scrapy常見命令及專案檔案介紹

一、Scrapy常見命令提示符CMD命令: (1)scrapy -h 檢視指令幫助。 (2)scrapy fetch http://baidu.com 直接爬取特定網頁。 (3)scrapy runspider scrapytest.py  執行特定爬蟲(前提要使用cd

Python資料爬蟲學習筆記(17)Scrapy糗事百科自動爬蟲

一、需求:在糗事百科主頁下,無需設定頁碼,自動爬取所有段子詳情頁的段子完整內容。 (1)糗事百科主頁: (2)段子詳情頁: 二、Scrapy實現思路:        在糗事百科主頁上自動提取出所有段子的詳情連結,在每個段字詳情頁中爬取段子內容。 三、網頁原始

資料結構學習筆記之棧(含數制轉換,括號匹配,表示式求值轉逆波蘭)

#include <iostream> #include <cstring> #include <ctype.h> #include <string> #include <cstring> #include <

Python資料爬蟲學習筆記(21)爬取京東商品JSON資訊並解析

一、需求:有一個通過抓包得到的京東商品的JSON連結,解析該JSON內容,並提取出特定id的商品價格p,json內容如下: jQuery923933([{"op":"7599.00","m":"9999.00","id":"J_5089253","p":"7099.00"}

Python資料分析學習筆記(1)numpy模組基礎入門

        numpy模組可以進行高效的資料處理,並提供了陣列的支援,很多模組都依賴他,比如pandas、scipy、matplotlib等,因此這個模組是基礎。 (1)匯入: import numpy (2)建立一維和二維陣列: #建立一維陣列 x=numpy.

資料結構學習筆記——C++實現雙向迴圈連結串列模板類(超詳解)

定義了兩個標頭檔案分別放置結點類模板(Node.h)和雙鏈表模板(DoubleLinkList.h), 然後在原始檔的main函式中測試。 Node.h #pragma once # include <iostream> template <class

1008-1-鄧俊輝資料結構學習筆記 8.1-伸展樹

高階搜尋樹 文章目錄高階搜尋樹伸展樹概述逐層伸展雙層伸展綜合評價 伸展樹 對於維護平衡因子,感覺很麻煩,希望拋棄掉平衡因子,使用更加瀟灑的模式。 要求: 對於伸展樹來說,也不做過多掌握 主要明白利用資料的區域性性,我們可以實施的新策略 概述 背景知識補充:

資料結構學習筆記——線性表之順序表(c語言實現)

1.概念 順序表即線性表的順序儲存結構 ,指的是用一段地址連續的儲存單元依次儲存線性表資料元素。線上性表中,每個資料元素的型別都相同,一般可以用一維陣列來實現順序儲存結構。 2.實現 (1)建立順序表的結構 利用c語言結構體來建立順序表的結構,順序表結構體中

Python資料分析學習筆記(6)資料規約實戰--以主成分分析PCA為例

一、相關理論: 1、資料規約:產生更小且保持資料完整性的新資料集。意義在於降低無效、錯誤資料;降低儲存成本;少量且具有代表性的資料大幅加快,主要分為以下兩類: ①屬性規約:屬性合併或刪除無關維,目標是尋找最小子集使子集概率分佈儘可能與原來相同。     常用方法: (

資料結構學習筆記——堆疊之鏈式儲存結構(c語言實現)

棧的鏈式儲存結構使用單鏈表實現,同線性表一樣,鏈式儲存結構的堆疊在儲存空間的利用上顯得更加靈活,只要硬體允許一般不會出現溢位的情況。但鏈式棧相對於順序棧稍顯麻煩,若所需堆疊空間確定,順序棧顯得方便一些。關於鏈式和順序式的選擇視具體情況而定。 1.棧的鏈式儲存結構

資料結構學習筆記Day2-單鏈表(用java實現)

一、首先說一下線性表 1. 什麼是線性表,線性表的邏輯特性? 1)有一個頭(表頭),有一個尾(表尾) 2)表頭與表尾之間的元素有且只有一個前驅元素,有且只有一個後繼元素 2.線性表有兩種儲存方式? 順序表和連結串列 3.順序表和連結串列的區別? 1)順序表是一邊