1. 程式人生 > >時間複雜度和空間複雜度的簡單講解

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

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

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

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

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

常見的時間複雜度有:
常數階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*n^3+2n+100則O(n)=n^3。

通常我們計算時間複雜度都是計算最壞情況
時間複雜度的計算:
(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的話,則迴圈不能執行,時間複雜度是0。

空間複雜度
空間複雜度是對一個演算法在執行過程中臨時佔用儲存空間大小的量度。
計算方法:
①忽略常數,用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)

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