1. 程式人生 > >大O表示法(向往羅馬)

大O表示法(向往羅馬)

while 增加 || key 標記 記憶 n) static 依次

一、身在斯洛文尼亞的阿拉裏克得到斯提裏科被殺的消息後,仰天大笑:“終於沒有人能阻止我去羅馬了。”
當他手下的將軍問:“不知大王打算走哪條路去羅馬?”
西哥特王哈哈大笑,說出了那句千古名言:All roads lead to Rome

二、最近看了Mark Allen Weiss的《數據結構與算法分析---java語言描述》,看到第二章的算法分析,看到裏面對算法時間預估方式用到的相對增長率(relative rate of growth)。同時為了準確計算不同算法的相對增加率,而使用到了大O標記法,這裏結合對大學知識僅存的一點記憶,對大O標記法進行一個簡單的對比分析。

三、首先用數組的排序證明大O標記法的使用方式

  1.冒泡排序

  

 *
 * @author zmm
 * @date 2017年7月30日
 * @version 1.0
 *
 */
public class SimpleSort {

    public static void bubbleSort(final int[] array) {
        if (array == null || array.length == 0) {
            throw new IllegalArgumentException("array");
        }
        
        int length = array.length;
        for (int outLoop = length - 1; outLoop > 0; outLoop-- ) {
            for (int innerLoop = 0; innerLoop < outLoop; innerLoop++) {
                if (array[innerLoop] > array[innerLoop + 1]) {
                    swap(array, innerLoop, innerLoop + 1);
                }
            }
        }
    }
    
    private static void swap(final int[] array, final int left, final int right) {
        int temp = array[left];
        array[left] = array[right];
        array[right] = temp;
    }
}

冒泡排序先從數組最左邊開始,比較第1個和第2個元素的值,值比較高的往數組的高位排,然後依次比較第2和第3個元素,值比較大的往高位排,一直比較到倒數第2個和倒數第1個元素,這稱為第一趟排序,這一趟就能確定數組中值最大的那個元素,並把這個最大的元素排到數組的最高位。
依次類推,第二趟排序會確定數組中第二大的元素,並把它排在最大的元素前邊。

  二、選擇排序

  

 * @version 1.0
 *
 */
public class SimpleSort {

    public static void selectionSort(final int[] array) {
        if (array == null || array.length == 0) {
            throw new IllegalArgumentException("array");
        }
        
        int length = array.length;
        int minIndex;
        for (int outLoop = 0; outLoop < length - 1; outLoop++) {
            minIndex = outLoop;
            for (int innerLoop = outLoop + 1;innerLoop < length; innerLoop++) {
                if (array[innerLoop] < array[minIndex]) {
                    minIndex = innerLoop;
                }
            }
            swap(array, outLoop, minIndex);
        }
    }
    
    private static void swap(final int[] array, final int left, final int right) {
        int temp = array[left];
        array[left] = array[right];
        array[right] = temp;
    }
}

選擇排序的過程是從左向右掃描數組,並從中找出最小值的元素,把它放在左邊已知的最小位置上,比如第一趟掃描,找出最小的元素後,將該元素放到數組的下標0處。第二趟掃描從下標1開始掃描,找出最小元素後,放到下標1處。總共需要掃描n-1次,就能使該數組處於有序狀態。
  3、
/**
 *
 *
 * @author beanlam
 * @date 2016年3月9日 下午11:26:20
 * @version 1.0
 *
 */
public class SimpleSort {
    public static void insertionSort(final int[] array) {
        if (array == null || array.length == 0) {
            throw new IllegalArgumentException("array");
        }
        
        int length = array.length;
        for (int outLoop = 1; outLoop < length; outLoop++) {
            int temp = array[outLoop];
            for (int innerLoop = outLoop - 1; innerLoop >= 0; innerLoop--) {
                if (array[innerLoop] > temp) {
                    array[innerLoop + 1] = array[innerLoop];
                    if (innerLoop == 0) {
                        array[innerLoop] = temp;
                    }
                } else {
                    array[innerLoop + 1] = temp;
                    break;
                }
            }
        }
    }
    
    public static void insertionSort1(final int[] array) {
        if (array == null || array.length == 0) {
            throw new IllegalArgumentException("array");
        }
        
        int length = array.length;
        int temp;
        int innerLoop;
        for (int outLoop = 1; outLoop < length; outLoop++) {
            temp = array[outLoop];
            innerLoop = outLoop;
            while (innerLoop > 0 && array[innerLoop - 1] >= temp) {
                array[innerLoop] = array[innerLoop-1];
                --innerLoop;
            }
            array[innerLoop] = temp;
        }
    }
     
    private static void swap(final int[] array, final int left, final int right) {
        int temp = array[left];
        array[left] = array[right];
        array[right] = temp;
    }
}
插入排序的精髓在於先令局部有序,先令左邊一部分數據有序,然後這部分有序的元素的下一位再與這些有序的元素比較,尋找合適自己站立的位置,插隊排進去,插隊也意味著右邊的有序元素要挪動身子。
一下提供基於for循環和while循環的兩種插入排序實現方式


四、結論分析

大O表示法只是一個粗略的估算值,它關註與隨著數據量N的增大,算法速度的變化。

對於數組某個下標的賦值,算法消耗的時間是個常數K
對於線性的查找,算法的消耗時間與N成正比。
對於二分查找,算法消耗時間與log(N)成正比。

大O表示法通常會忽略常數,因為它關註的是算法的消耗時間隨著N的變化而怎麽變化。常數通常與處理器芯片或者編譯器有關。

大O表示法(向往羅馬)