數據結構筆記淺記(三)空間複雜度

用於衡量算法佔用內存空間隨着數據量變大時的增長趨勢。這個概念與時 間複雜度非常類似,只需將“運行時間”替換爲“佔用內存空間”。

 

算法在運行過程中使用的內存空間主要包括以下幾種。

        ‧ 輸入空間:用於存儲算法的輸入數據。

        ‧ 暫存空間:用於存儲算法在運行過程中的變量、對象、函數上下文等數據。

                    暫存空間可以進一步劃分爲三個部分

                               ‧ 暫存數據:用於保存算法運行過程中的各種常量、變量、對象等。

                                ‧ 棧幀空間:用於保存調用函數的上下文數據。系統在每次調用函數時都會在棧頂部創建一個棧幀,函數 返回後,棧幀空間會被釋放。

                                ‧ 指令空間:用於保存編譯後的程序指令,在實際統計中通常忽略不計。

        ‧ 輸出空間:用於存儲算法的輸出數據。

一般情況下,空間複雜度的統計範圍是“暫存空間”加上“輸出空間”。在分析一段程序的空間複雜度時,我們通常統計暫存數據、棧幀空間和輸出數據三部分。

 

與時間複雜度不同的是,我們通常只關注最差空間複雜度。這是因爲內存空間是一項硬性要求,我們必須 確保在所有輸入數據下都有足夠的內存空間預留。

        1. 以最差輸入數據爲準:

        2. 以算法運行中的峯值內存爲準:

        ***在遞歸函數中,需要注意統計棧幀空間。***

遞歸和循環的區別:

    循環空間複雜度:𝑂(1) ,在循環中每次調用的返回後,都釋放棧幀空間;

   遞歸空間複雜度:𝑂(𝑛) ,在遞歸每次調用後同時存在多個未返回的遞歸函數,從而佔用棧幀空間。

 

設輸入數據大小爲 n,常見的空間複雜度類型(從低到高排列)。

數學表示:𝑂(1) < 𝑂(log 𝑛) < 𝑂(𝑛) < 𝑂(𝑛2 ) < 𝑂(2𝑛)

文字描述:常數階 < 對數階 < 線性階 < 平方階 < 指數階

常數階常見於數量與輸入數據大小 𝑛 無關的常量、變量、對象。 需要注意的是,在循環中初始化變量或調用函數而佔用的內存,在進入下一循環後就會被釋放,因此不會累 積佔用空間,空間複雜度仍爲 𝑂(1) 。

 

線性階常見於元素數量與 𝑛 成正比的數組、鏈表、棧、隊列等。

 

平方階常見於矩陣和圖,元素數量與 𝑛 成平方關係。

 

指數階常見於二叉樹。層數爲 𝑛 的“滿二叉樹”的節點數量爲 2 𝑛 − 1 ,佔用 𝑂(2𝑛) 空間。

 

對數階常見於分治算法。例如歸併排序,輸入長度爲 𝑛 的數組,每輪遞歸將數組從中點處劃分爲兩半,形成 高度爲 log 𝑛 的遞歸樹,使用 𝑂(log 𝑛) 棧幀空間。

 

理想情況下,我們希望算法的時間複雜度和空間複雜度都能達到最優。然而在實際情況中,同時優化時間復 雜度和空間複雜度通常非常困難。 降低時間複雜度通常需要以提升空間複雜度爲代價,反之亦然。我們將犧牲內存空間來提升算法運行速度的 思路稱爲“以空間換時間”;反之,則稱爲“以時間換空間”。 在大多數情況下,時間比空間更寶貴,因此“以空間換時間”通 常是更常用的策略。當然,在數據量很大的情況下,控制空間複雜度也非常重要。

 

「函數 function」可以被獨立執行,所有參數都以顯式傳遞。

「方法 method」與一個對象關聯,被隱式傳遞 給調用它的對象,能夠對類的實例中包含的數據進行操作。

 

下面以幾種常見的編程語言爲例來說明。

         ‧ C 語言過程式編程語言,沒有面向對象的概念,所以只有函數。但我們可以通過創建結構體(struct) 來模擬面向對象編程,與結構體相關聯的函數就相當於其他編程語言中的方法。

        ‧ Java 和 C# 面向對象的編程語言,代碼塊(方法)通常作爲某個類的一部分。靜態方法的行爲類似於 函數,因爲它被綁定在類上,不能訪問特定的實例變量。

         ‧ C++ 和 Python 既支持過程式編程(函數),也支持面向對象編程(方法)

 

***複雜度,其反映的是增長趨勢***

 

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