1. 程式人生 > 其它 >資料結構基礎知識補充

資料結構基礎知識補充

資料結構基礎知識補充

  • 參考文章:https://blog.csdn.net/f553762019/article/details/107939161

1.定義

資料結構:是相互之間存在一種或多種特定關係的資料元素集合。

1.1 基本結構

  • 集合
  • 線性結構
  • 樹形結構
  • 圖狀結構
  • 網狀結構

2.演算法分析

2.1 演算法

演算法:是對特定 問題求解步驟的一種描述,它是指令有限序列,其中每一條指令表示一個多個操作。

  • 一個演算法還具有5個重要特性:
    • 有窮性
    • 確定性
    • 可行性
    • 輸入
    • 輸出

2.2 演算法設計的要求

  • 正確性
  • 可讀性
  • 健壯性
  • 效率與低儲存量需求

2.3演算法效率的度量

  • 事後統計法
  • 事前分析估演算法。
2.3.1時間複雜度

在如下所示的兩個N*N矩陣相乘的演算法中,"乘法"運算是"矩陣相乘問題"的基本操作。整個演算法執行時間與該基本操作(乘法)重複執行的次數 n3 成正比。記作T(n)=O(n3)。

// N*N矩陣相乘的演算法
for(i=1;i<=n;++i){
    for(j=1;j<=n;++j){
        c[i][j]=0;
        for(k=1;k<=n;++k){
            c[i][j]+=a[i][j]*b[k][j];
        }
    }
}

一般情況下,演算法中基本操作重複執行的次數是問題規模 n 的某個函式 f(n),演算法的時間度量記作T(n)=O(n)

它表示雖問題規模 n 的增大,演算法執行時間的增長率和 f(n) 的增長率相同,稱做演算法的漸進時間複雜度,簡稱時間複雜度

  • 常見的時間複雜度量級
    • 常數階O(1)
    • 對數階O(log N)
    • 線性階O(n)
    • 線性對數階O(n log N)
    • 平方階O(n2)
    • 立方階O(n3)
    • K次方階O(nk)
    • 指數階(2n)
  • 常數階O(1)

無論程式碼執行了多少行,只要是沒有迴圈等複雜結構,那這個程式碼的時間複雜度就都是O(1),如:

int i = 1;
int j = 2;
++i;
j++;
int m = i + j;

上述程式碼在執行的時候,它消耗的時候並不隨著某個變數的增長而增長,那麼無論這類程式碼有多長,即使有幾萬幾十萬行,都可以用O(1)來表示它的時間複雜度。

  • 線性階O(n)

這個在最開始的程式碼示例中就講解過了,如:

for(i=1; i<=n; ++i)
{
   j = i;
   j++;
}
  • 這段程式碼,for迴圈裡面的程式碼會執行n遍,因此它消耗的時間是隨著n的變化而變化的,因此這類程式碼都可以用O(n)來表示它的時間複雜度。

  • 對數階O(log N)
    int i = 1;
    while(i<n)
    {
      i = i * 2;
    }
    
    • 從上面程式碼可以看到,在while迴圈裡面,每次都將 i 乘以 2,乘完之後,i 距離 n 就越來越近了。我們試著求解一下,假設迴圈x次之後,i 就大於 2 了,此時這個迴圈就退出了,也就是說 2 的 x 次方等於 n,那麼 x = log 2n。也就是說當迴圈 log 2n 次以後,這個程式碼就結束了。因此這個程式碼的時間複雜度為:O(log n)
  • 線性對數階O(n log N)
    • 線性對數階O(n log N) 其實非常容易理解,將時間複雜度為O(log n)的程式碼迴圈N遍的話,那麼它的時間複雜度就是 n * O(log N),也就是了O(n log N)。
    • 就拿上面的程式碼加一點修改來舉例:
      for(m=1; m<n; m++)
      {
          i = 1;
          while(i<n)
          {
              i = i * 2;
          }
      }
    
  • 平方階O(n2)
    • 平方階O(n²) 就更容易理解了,如果把 O(n) 的程式碼再巢狀迴圈一遍,它的時間複雜度就是 O(n²) 了。 舉例:

    • for(x=1; i<=n; x++)
        {
           for(i=1; i<=n; i++)
            {
               j = i;
               j++;
            }
        }
      
    • 這段程式碼其實就是嵌套了2層n迴圈,它的時間複雜度就是 O(n*n),即 O(n²)
      如果將其中一層迴圈的n改成m,即:

    •  for(x=1; i<=m; x++)
        {
           for(i=1; i<=n; i++)
            {
               j = i;
               j++;
            }
        }
      
    • 那它的時間複雜度就變成了 O(m*n)

  • 立方階O(n³)、K次方階O(n^k)

    • 參考上面的O(n²) 去理解就好了,O(n³)相當於三層n迴圈,其它的類似。
    • 除此之外,其實還有 平均時間複雜度、均攤時間複雜度、最壞時間複雜度、最好時間複雜度 的分析方法,有點複雜,這裡就不展開了。
2.3.2 空間複雜度

類似於演算法的時間複雜度,本書中以空間複雜度,作為演算法所需儲存空間的量度,記作S(n)=O(f(n))

空間複雜度是對一個演算法在執行過程中臨時佔用儲存空間大小的一個量度,同樣反映的是一個趨勢,我們用 S(n) 來定義。

空間複雜度比較常用的有:O(1)、O(n)、O(n²),我們下面來看看:

  • 空間複雜度O(1)

    如果演算法執行所需要的臨時空間不隨著某個變數n的大小而變化,即此演算法空間複雜度為一個常量,可表示為 O(1)
    舉例:

int i = 1;
int j = 2;
++i;
j++;
int m = i + j;

程式碼中的 i、j、m 所分配的空間都不隨著處理資料量變化,因此它的空間複雜度 S(n) = O(1)

  • 空間複雜度O(n)
    int[] m = new int[n]
    for(i=1; i<=n; ++i)
    {
       j = i;
       j++;
    }
    

    這段程式碼中,第一行new了一個數組出來,這個資料佔用的大小為n,這段程式碼的2-6行,雖然有迴圈,但沒有再分配新的空間,因此,這段程式碼的空間複雜度主要看第一行即可,即 S(n) = O(n)