1. 程式人生 > 其它 >線性查詢法02:迴圈不變數和演算法複雜度

線性查詢法02:迴圈不變數和演算法複雜度

迴圈不變數

public static<E> int search(E[] arr, E target){
    /**
     * 迴圈不變數,就是在迴圈中始終遵守的原則
     * 因為在arr[0...i-1]中沒有找到目標,所以才繼續迴圈
     * 這個arr[0...i-1]就是迴圈不變數,在寫迴圈時一定要清楚迴圈不變數是什麼
     */
    for (int i = 0; i < arr.length; i++) {
        /**
     	 * 迴圈體就是為了維持迴圈不變數,證明演算法的正確性
    	 */
        if (target == arr[i]) {
            return i;
        }
    }
    return -1;
}

演算法複雜度

複雜度描述的是隨著資料規模n的增大,演算法效能的變化趨勢

在複雜度分析中,常數不重要(線性查詢法的複雜度是O(n))

T1 10000n O(n)
T2 2n^2 O(n^2)
當n > 5000,T2複雜度大於T1,並且規模越大,差距越大

常見的時間複雜度

/**
 * 遍歷一個n*n的二維陣列,n指維度,複雜度是O(n^2)
 */
for (int i = 0; i < n; i++){
    for (int j = 0; j < n; j++){
        return arr[i][j];
    }
}

/**
 * 遍歷一個a*a的二維陣列,其中a*a=n,n指元素總數,複雜度是O(n)
 * 因此一定要清楚n到底指的是誰
 */
for (int i = 0; i < a; i++){
    for (int j = 0; j < a; j++){
        System.out.println(arr[i][j]);
    }
}

/**
 * 輸出數字num的二進位制位數,n和要計算的次數有關,每計算一次,規模除以2,複雜度是O(logn)
 * 對log函式而言,底數不同相差的是常數,因此忽略底數
 */
while (n){
    System.out.println(num % 2);
    num /= 2;
}

/**
 * 輸出數字num的約數,約數是成對出現的,只要迴圈到根號num就可以拿到所有約數,因此n指根號num
 * 複雜度是O(sqrt{n})
 */
for (int i = 1; i * i <= n; i++) {
    if (n % i == 0){
        System.out.println(i);
        System.out.println(n / i);
    }
}

/**
 * 輸出長度為n的二進位制數字,每增加一個長度,規模翻倍,複雜度是O(2^n)
 */

/**
 * 輸出長度為n的陣列的全排列,複雜度是O(n!)
 */

/**
 * 判斷數字n是否是偶數,只用執行常數量級的語句,複雜度是O(1)
 */

總結:O(1) < O(logn) < O(sqrt(n)) < O(n) < O(nlogn) < O(n^2) < O(2^n) < O(n!)

測試線性查詢演算法效能

public class Algorithm {

    public static void main(String[] args) {

        Integer n = 10000000;
        Integer[] arr = ArrayGenerator.generatorArray(n);
        Integer target = n;

        /**
         * System.nanoTime()方法列印時間戳
         */
        long startTime = System.nanoTime();

        /**
         * 迴圈多次測試時間效能,比一次性測試更穩定,結果也更真實
         */
        for (int i = 0; i < 100; i++) {
            LinerSearch.search(arr, target);
        }

        long endTime = System.nanoTime();
        System.out.println((endTime - startTime) / 1000000000.0 + "秒");
    }
}

class LinerSearch {

    private LinerSearch(){}

    public static<E> int search(E[] arr, E target){
        for (int i = 0; i < arr.length; i++) {
            if (arr[i].equals(target)) {
                return i;
            }
        }
        return -1;
    }
}

/**
 * 建立一個根據n生成陣列的類
 */
class ArrayGenerator {
    private ArrayGenerator(){}

    public static Integer[] generatorArray(Integer n){

        Integer[] arr = new Integer[n];

        for (int i = 0; i < n; i++) {
            arr[i] = i;
        }
        return arr;
    }
}