回覆列表
  • 1 # 騰訊技術工程

    邏輯程式碼計算最佳化

    在不考慮面向物件的情況下,先讓我們先回憶下c語言中的3大結構。

    1、順序結構

    2、分支(條件)結構

    3、迴圈結構

    這三個結構任意組合構成了我們書寫的邏輯程式碼(演算法)。下面我們就根據這常用的三種結構進行調優。注意,下文中的使用的語言為JavaScript,但考慮大的是大部分語言的情況。

    程式碼在計算機中實際都是一條條語句執行的,分支和迴圈結構在使用了jump語句實現了語句跳轉之後,實際上也變成了一個順序結構。如果程式碼以順序結構執行,則可以透過程式計數器自增讓程式碼順序執行。如果是jump跳轉語句則會發生定址,計算等額外步驟。

    [ 彙編 ]

    這裡c語言程式碼中寫了一個普通的迴圈。但是在計算機中實際執行時類似右邊goto版本的。每一個goto會加重計算機的計算,所以在考慮效能的情況下儘量使用順序結構。

    最佳化迴圈

    常見的迴圈有

    1、while

    2、for

    3、do…while

    注意的是迴圈中while與for是先判斷在開始迴圈,do…while是先執行一次後判斷在開始迴圈

    迴圈中兩種方案調優

    1、減少每次迴圈處理的事務

    2、減少迴圈的次數

    在迴圈判斷條件中,通常我們將某個物件的屬性進行判斷比如

    實際上在計算機的語句為

    初始化(一次)

    一次i初始化(var i)

    一次i賦值(i = 0)

    判斷(n次)

    i值查詢(i)

    array值查詢(array)

    透過array找到length(array.length)

    i 與 length 比較(i < array.length)

    後處理,自增(n - 1次)

    i取值(i)

    計算i + 1(i + 1)

    將結果賦值給(i = i + 1)

    這次判斷實際上有四個語句組成,在看看下面的程式碼

    在這個判斷中實際上在計算機的語句為:

    一次i值查詢。

    一次len值查詢

    透過array找到length

    i 與 length 比較

    這裡在單次迴圈中語句減少了一條。在多次迴圈下,將減少了n條計算機語句。

    如果是簡單的數值比較我們還可以使用倒序迴圈方式

    這次實際上在計算機的語句為

    初始化(一次)

    i初始化(var i)

    array值查詢(array)

    透過array找到length(array.length)

    i賦值(i = array.length)

    判斷(n次)

    i取值(i)

    計算i - 1(i - 1)

    將結果賦值給(i = i - 1)

    後處理,自增(n-1次)

    實際上這樣的語句確實少了挺多,但是必須是在順序無關和數值比較的前提下。因為部分語言會提供數值與布林值的自動轉換(像java這麼寫就會報錯)

    減少使用遞迴

    談到迴圈,自然也會談到遞迴。遞迴最簡單說就是某個函式繼續呼叫某個函式,一般是自己呼叫自己。

    一個程序。有資料區,堆疊,PCB等內容。堆疊的大小在程序開啟的時候基本確定,棧能儲存執行時的區域性變數,和函式呼叫資訊。如果發生遞迴,則會在棧中持續新增內容。若執行函式需要用到區域性變數,或者呼叫函式不是最後一句時。將會發生中斷。中斷後,本次執行的上下文環境也會被儲存進棧內,形成一個呼叫棧。

    [ 遞迴 ]

    發生一次中斷,會觸發CPU的中斷處理,儲存中斷資訊現場,指令跳轉。恢復時又會跳轉指令,恢復中斷現場資訊。如果非必要,請不要使用遞迴。

    棧的大小是固定的,如果超過棧的大小,就會有爆棧的可能(著名的stack overflow)。部分語言有尾呼叫最佳化,可以讓遞迴不儲存中斷資訊。

    最佳化選擇

    常見的選擇有:

    if…else 更適合範圍匹配

    switch…case 更適合單值匹配

    不管使用的是if…else還是switch…case,判斷都是按書寫的順序開始執行的。所以我們應該把最可能出現的情況放在第一位。

    由於選擇結構也會觸發指令跳轉,我們應該使用巢狀的if…else,使用樹的形式,讓到達每一個結果的情況儘可能的少。

  • 中秋節和大豐收的關聯?
  • 如果你現在買房,你打算買哪裡的?