1. 程式人生 > >python演算法——大O表示法

python演算法——大O表示法

大O表示法

大O表示法的樣子為 O(運算元)
大O表示法指出了演算法的速度有多快
它的好處在於,當我們引用別人的演算法時,瞭解了它的大O表示法會對我們大有益處。(一般情況下用處不大,但瞭解總是好的)

不同的大O執行時間

當要找出一堆數中最大的數時:

1.遍歷所有的數
2.找出最大數

def Max(n):
    for k in n:
        max_number = 0
        if max_number < k:
            max_number = k
    return max_number


print(Max([1, 3, 5, 7, 9]))

這裡需要把列表所有的元素都檢查一遍,因此執行時間也就是列表中所有元素檢查一遍的時間。用大O表示法表示為O(n)

當把一堆數按從小到大排列時:

1.找出最小的數,把它加入新列表並從原列表中刪除
2.有多少數執行多少次

def find_min(n):
    minest = n[0]
    minest_index = 0
    for i in range(1, len(n)):
        if minest > n[i]:
            minest = n[i]
            minest_index = i
    return minest_index


def array(n):
    NewArr = []
    for i in range(len(n)):
        minest = find_min(n)
        NewArr.append(n.pop(minest))
    return NewArr


print(array([9, 7, 5, 3, 1]))

這裡每次都需要遍歷所有數,遍歷的次數為元素的數量。大O表示法為O(n*n),即O(n^2)
*注:即使下一次需要遍歷的數量比上一次少一,但它還是n。

大O表示法中的常量

一些常見的大O表示法演算法圖解
基於每秒執行10次計算的,但計算機執行速度並不是這樣。只是為了有個大概的計量,便於瞭解之間的差別。

常量c

比較一下下面兩個列印列表的函式:
1.列印一個列表

def print_number1(list):
    for k in list:
        print(k)


print_number1([1, 3, 5, 7, 9])

2.列印一個列表,每列印一個數字休眠1秒

from time import sleep


def print_number2(list):
    for k in list:
        print(k)
        sleep(1)


print_number2([1, 3, 5, 7, 9])

可以看出兩個函式的大O表示法都為 O(n),因為它們都遍歷了一個列表。但是可以明顯感覺到print_number1的執行速度要比print_number2快許多。因為它沒有每次執行後休眠1秒。但從大O表示法來看二者的執行速度是一樣的,但print_number1的執行速度要快。在大O表示法中n指的其實是c*n。

這個c指的是演算法所需的固定時間,被稱為常量。print_number1指的是 10毫秒*n 。
print_number2指的是 1秒*n。

通常這個常量是不被考慮進來的,因為大O執行時間不同,這個常量無關緊要。

舉個例子:
用上圖的簡單查詢和二分查詢來說。

設簡單查詢的執行常量為10毫秒,二分查詢的執行常量為10秒。
當元素數量很多(10億)的時候
二者的執行時間為
簡單查詢:10毫秒*10億=1億秒
二分查詢:10秒*log(10億)=300秒
很明顯二分查詢要比簡單查詢快的多,所以常量基本沒什麼影響。

但有時候常量有的影響可能會很大,比如說上例中列印列表的函式。print_number1的常量比print_number2小,但它們的執行時間都為O(n)
所以print_number1的執行速度更快。實際上print_number1的執行速度確實要快。相對於糟糕情況,遇上平均情況的可能性要大的多。

平均情況與最糟情況

這裡要涉及到快速排序
在快速排序中,效能的高低取決於所選的,基準值。
假如你每次都將第一個元素作為基準值,且元素是有序的,由於快速排序不檢查陣列是否有序,因此它依舊會按照程式執行
演算法圖解
注意這裡數列沒有被分為兩半,其中一個子序列總是為空。導致了呼叫棧很長。

如果每次的基準值都是中間元素呢
演算法圖解
這裡呼叫棧短很多,因為每次都將陣列分為兩半,很快就到達了基線條件。因此呼叫棧短很多。

以上兩種情況就是最糟情況與最佳情況。
最糟情況下:棧的長度為O(n),每層都涉及O(n)個元素。所以執行時間為O(n*n)
最佳情況下:棧的長度為O(logn),每層涉及O(n)個元素。所以執行時間為O(logn*n)
這裡的最佳情況也就是平均情況。只要你每次選基準值都是隨機的,快速排序的執行時間都為O(logn*n)。