資料結構 第6篇 演算法效率的度量
阿新 • • 發佈:2021-01-19
開心一刻:
在網上碰上一群流氓並不可怕,可怕的是碰上了一堆流氓軟體。
演算法效率的度量
常見時間複雜度的比較:
O(1) < O(logn) < O(n) < O(n*logn) < O(n*n) < O(n*n*n) < O(2^n^) < O(n!) < O(n^n^) 當演算法的時間複雜度為 O(2^n^) , O(n!) 或 O(n^n^)時,即使n的值很小,實際執行時間也是不可接受的。
演算法分析示例:
int find(int a[], int n, int v)
{
int ret = -1;
for(int i=0; i<n; i++)
{
if( a[i] == v )
{
ret = i;
break;
}
}
return ret;
}
int arr[5] = {1,2,3,4,5};
int min = find(arr, 5, 1); // 最好的情況,執行1次迴圈,O(1)
int max = find(arr, 5, 5); // 最壞的情況,執行n次迴圈,O(n)
演算法最好與最壞情況的意義:
當演算法在最壞情況下仍然能滿足需求時,可以推斷,演算法的最好情況和平均情況都滿足需求。 若沒有特殊說明時,所分析演算法的時間複雜度都是指最壞時間複雜度。
演算法的空間複雜度( Space Complexity )
---定義:S(n) = S( f(n) )
n為演算法的問題規模
f(n)為空間使用函式,與n相關
推倒時間複雜度的方法同樣適用於空間複雜度
例:當演算法所需要的空間是常數時,空間複雜度為S(1)
空間複雜度的練習:
long suml(int n) // 1 (變數所佔的記憶體單元)
{
long ret = 0; // 1
int* array = new int[n]; // n
for(int i=0; i<n; i++) // 1
{
array[i] = i + 1;
}
for(int i = 0; i < n; i++) // 1
{
ret += array[i];
}
delete[] array;
return ret;
}
// ===> 所需單位記憶體: n + 4
// ===> 空間複雜度: S(n + 4) = S(n)
空間與時間的策略:
---大多數情況下,演算法的時間複雜度更令人關注
---如果有必要,==可以通過增加額外空間降低時間複雜度==
--- 同理,也可通過增加演算法的耗時降低空間複雜度
空間換時間 — 示例分析:
/*
/*
問題: (空間換時間)
在一個由自然數1-1000中某些數字所組成的陣列中,每個數字可能出現零次或者多次。
設計一個演算法,找出出現次數最多的數字。
*/
#include <iostream>
using namespace std;
void search(int a[], int len) // O(n)
{
int sp[1000] = {0}; // 這個初始化很重要,0-999個空盒子(輔助空間換時間)
int max = 0;
for(int i=0; i<len; i++) // 遍歷a[]中元素,這是主要耗時,隨著陣列長度的增加而增加;後兩個迴圈耗時是一定的;
{
sp[a[i] - 1]++; // 遍歷減一 作為陣列sp[]的下標使用,0-999個盒子中記錄了a[]陣列元素出現的次數
}
for(int i=0; i<1000; i++) // 出現的次數和最大值進行比較,最終確定出現次數最多的值
{
if( max < sp[i] )
{
max = sp[i];
}
}
for(int i=0; i<1000; i++)
{
if( max == sp[i] ) // 當出現次數最多時,輸出最多值
{
cout << i + 1 << endl;
}
}
}
int main(int argc, char* argv[])
{
int a[] = {1, 1, 3, 4, 5, 6, 6, 6, 3, 3};
search(a, sizeof(a)/sizeof(*a));
return 0;
}
面試題:
當兩個演算法的大O表示法相同時,是否意味著兩個演算法的效率完全相同?
答: 只能說明兩個演算法的效率事同一個級別的。
(考察了演算法時間複雜度的理解和演算法效率的理解)
總結:
--- 般而言,工程中使用的演算法,時間複雜度不超O(n*n*n)
--- 演算法分析設計時,重點考慮最壞情況下的時間複雜度
--- 資料結構中重點關注演算法的時間複雜度
--- 大O表示法同樣適用於演算法的空間複雜度
--- 時間換空間是工程開發中常用的策略
感謝關注,文章持續高速更新中······