時間複雜度和空間複雜度的簡單講解

一個算法的優劣主要從算法的執行時間和所需要佔用的存儲空間兩個方面衡量。

把今年很流行,淡淡的基佬紫送給各位看官,原諒綠就算了,怕被打死。

文章最後,舉例使用二分查找和斐波那契的遞歸和迭代方法,分別說明時間和空間複雜度。

時間複雜度:
首先要說的是,時間複雜度的計算並不是計算程序具體運行的時間,而是算法執行語句的次數。
當我們面前有多個算法時,我們可以通過計算時間複雜度,判斷出哪一個算法在具體執行時花費時間最多和最少。

常見的時間複雜度有:
常數階O(1),
對數階O(log2 n),
線性階O(n),
線性對數階O(n log2 n),
平方階O(n^2),
立方階O(n^3)
k次方階O(n^K),
指數階O(2^n)。
隨着n的不斷增大,時間複雜度不斷增大,算法花費時間越多。

計算方法
①選取相對增長最高的項
②最高項係數是都化爲1
③若是常數的話用O(1)表示
如f(n)=2*n3+2n+100則O(n)=n3。

通常我們計算時間複雜度都是計算最壞情況
時間複雜度的計算:
(1)如果算法的執行時間不隨着問題規模n的增加而增長,即使算法中有上千條語句,其執行時間也不過是一個較大的常數。此類算法的時間複雜度是O(1)。

        int x=1;
	while (x <10)
	{
		x++;
	}

該算法執行次數是10,是一個常數,用時間複雜度表示是O(1)。

(2)當有若干個循環語句時,算法的時間複雜度是由嵌套層數最多的循環語句中最內層語句的頻度f(n)決定的。

	for (i = 0; i < n; i++)
	{
		for (j = 0; j < n; j++)
		{
			;
		}
	}

該算法for循環,最外層循環每執行一次,內層循環都要執行n次,執行次數是根據n所決定的,時間複雜度是O(n^2)。

(3)循環不僅與n有關,還與執行循環所滿足的判斷條件有關。

int i=0;
while (i < n && arr[i]!=1)
	{
		i++;
	}

在此循環,如果arr[i]不等於1的話,時間複雜度是O(n)。如果arr[i]等於1的話,則循環執行一次判斷跳出,時間複雜度是O(1)。

空間複雜度
空間複雜度是對一個算法在運行過程中臨時佔用存儲空間大小的量度。
計算方法:
①忽略常數,用O(1)表示
②遞歸算法的空間複雜度=遞歸深度N*每次遞歸所要的輔助空間
③對於單線程來說,遞歸有運行時堆棧,求的是遞歸最深的那一次壓棧所耗費的空間的個數,因爲遞歸最深的那一次所耗費的空間足以容納它所有遞歸過程。

如:

int a;
int b;
int c;
printf("%d %d %d \n",a,b,c);

它的空間複雜度O(n)=O(1);

int fun(int n,)
{
int k=10;
if(n==k)
return n;
else
return fun(++n);
}

遞歸實現,調用fun函數,每次都創建1個變量k。調用n次,空間複雜度O(n*1)=O(n)。

#舉例說明

1:實現二分查找算法的遞歸及非遞歸。(分析時間複雜度及空間複雜度)

迭代算法

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<string.h>
#include<assert.h>

int BinarySearch(int arr[], int len, int num)
{
	assert(arr);

	int left = 0;
	int right = len - 1;
	int mid;

	while (left <= right)
	{
		mid = left + (right - left) / 2;

		if (num > arr[mid])
		{
			left = mid + 1;
		}
		else if (num < arr[mid])
		{
			right = mid - 1;
		}
		else
		{
			return mid;
		}
	}

	return -1;
}



int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9 };
	int length = sizeof(arr) / sizeof(arr[0]);
	int aim = 9;
	int result;

	result = BinarySearch(arr, length, aim);

	if (result == -1)
	{
		printf("Can't find %d\n", aim);
	}
	else
	{
		printf("%d at %d postion\n", aim,result + 1);
	}
	

	return 0;
}

二分查找時,每次都在原有查找內容進行二分,所以時間複雜度爲O(log2 n)
因爲變量值創建一次,所以空間複雜度爲O(1)

遞歸算法

int BinarySearchRecursion(int arr[5], int lef, int rig,int aim)
{
	int mid = lef + (rig - lef) / 2;

	
	if (lef <= rig)
	{
		if (aim < arr[mid])
		{
			rig = mid - 1;
			BinarySearchRecursion(arr, lef, rig, aim);
		}
		else if (arr[mid] < aim)
		{
			lef = mid + 1;
			BinarySearchRecursion(arr, lef, rig, aim);
		} 
		else if (aim == arr[mid])
		{
			return mid;
		}
		
	}
	else
		return -1;
	
}


int main()
{
	int arr[] = { 1,2,3,5,6, };
	int sz = sizeof(arr)/sizeof(arr[0]);
	int result;

	result = BinarySearchRecursion(arr, 0, sz - 1, 4);

	if (-1 == result)
	{
		printf("Can't find it.\n");
	}
	else
		printf("Aim at %d location\n", result+1);
}

時間複雜度爲O(log2 n)
每進行一次遞歸都會創建變量,所以空間複雜度爲O(log2 n)

2:實現斐波那契數列的遞歸及非遞歸。(分析時間複雜度及空間複雜度)

迭代算法

int FeiBoNaCciInteration(int a,int b,int num)
{
	int c;

	if (num <= 0)
		return -1;
	else if (num == 1)
		return a;
	else if (num == 2)
		return b;
	else
	{
		while (num - 2)
		{
			c = a + b;
			a = b;
			b = c;
			num--;
		}
		return c;
	}
	
}

int main()
{
	int n;
	int result;

	printf("Input n\n");
	scanf("%d", &n);

	result = FeiBoNaCciInteration(2, 3, n);//可自定義輸入第一個數和第二個數
	if (result == -1)
	{
		printf("Input Error!\n");
	}
	else
	{
		printf("n is %d\n", result);
	}

	return 0;
}

時間複雜度O(n)
空間複雜度爲O(1)

遞歸算法

int FeiBoNaCciRecursion(int num)
{
	if (num < 0)
		return -1;
	if (num <= 2 && num > 0)
		return 1;
	else
		return FeiBoNaCciRecursion(num - 1) + FeiBoNaCciRecursion(num - 2);
	
}

int main()
{
	int n;
	int result;

	printf("Input n\n");
	scanf("%d", &n);

	result = FeiBoNaCciRecursion(n);

	if (result == -1)
		printf("Input Error!\n");
	else
		printf("Result is %d\n", result);

	return 0;
}

時間複雜度爲O(2^n)
空間複雜度爲O(n)

歡迎在評論區留言提問,謝謝!

另外,如果覺得文章對你有用,右側邊欄點個打賞吧!

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