1. 程式人生 > >【資料結構】時間複雜度和空間複雜度

【資料結構】時間複雜度和空間複雜度

衡量一個演算法的複雜度:

即演算法的時間複雜度空間複雜度統稱為演算法的時間複雜度。

  • 時間複雜度

計算一下下面程式的迴圈語句總共會執行多少次?

void Test(int n)
{
	int iConut = 0;
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < n; ++j)
		{
			iCount++;
		}
	}
	for (int k = 0; k < 2 * n; ++k)
	{
		iCount++;
	}
	int count = 10;
	while (count--)
	{
		iCount++;
	}
}

很顯然    f(n)=n*n+2*n+10

時間複雜度就是一個函式,該函式計算的是執行基本操作的次數。

  • 演算法分析的分類:

演算法存在最好,平均和最壞情況: 

  1. 最壞情況:任意輸入規模的最大執行次數(上界)
  2. 平均情況:任意輸入規模的期望執行次數
  3. 最好情況:任意輸入規模的最小執行次數,通常最好情況不會出現(下界)  

例如:在一個長度為N的線性表中搜索一個數據x

最好情況: 1次比較

最壞情況: N次比較

平均情況: N/2次比較

在實際中通常關注的是演算法的最壞執行情況,即:任意輸入規模N,演算法的最長執行時間。

理由如下:

 一個演算法的最壞情況的執行時間是在任意輸入下的執行時間上界

對於某些演算法,最壞的情況出現的較為頻繁

大體上看,平均情況與最壞情況一樣差

      因此: 以般情況下使用O漸進表示法來計算演算法的時間複雜度

時間複雜度之大O漸進表示法:

一個演算法語句總的執行次數是關於問題規模N的某個函式,記為f(N) , N稱為問題的規模。語句總的執行次數記為T(N) , 當N不斷變化時, T(N)也在變化,演算法執行次數的增長速率和f(N)的增長速率相同。  則有T(N) =O(f(N)) ,稱O(f(n))為時間複雜度的O漸進表示法。

  • 一般演算法O(n)計算方法:
  1. 用常數1取代執行時間中的所有加法常數
  2. 在修改後的執行次數函式中,只保留最高階項
  3. 如果最高階項係數存在且不是1 ,則去除與這個項相乘的常數  
  • 空間複雜度

空間複雜度:函式中建立物件的個數關於問題規模函式表示式,空間複雜度是對一個演算法在執行過程中臨時佔用儲存空間大小的量度。空間複雜度不是程式佔用了多少bytes的空間,因為這個也沒太大意義,所以空間複雜度算的是變數的個數。空間複雜度計算規則基本跟實踐複雜度類似,也使用大0漸進表示法。

例如:

void BubbleSort(int* a, int n)
{
	assert(a);

	for (size_t end = n; end > 0; end--)
	{
		int exchange = 0;
		for (size_t i = 1; i < end; i++)
		{
			if (a[i - 1]>a[i])
			{
				Swap(&a[i - 1], a[i]);
				exchange = 1;
			}
		}
		if (exchange == 0)
		{
			break;
		}
	}
}

上面使用了常數個額外空間,所以空間複雜度為0(1)

long long* Fibonacci(size_t n)
{
	if (n == 0)
		return NULL;
	long long* fibArray = new long long[n + 1];
	fibArray[0] = 0;
	fibArray[1] = 1;
	for (int i = 2; i <= n; i++)
	{
		fibArray[i] = fibArray[i - 1] + fibArray[i - 2];
	}
	return fibArray;
}

此處動態開闢了N個空間,空間複雜度為O(N)

常見的時間複雜度計算函式: