淺析七種經(jīng)典排序算法

本文分析冒泡、選擇了赵、插入潜支、希爾、快速柿汛、歸并和堆排序冗酿,為不影響閱讀體驗(yàn)埠对,將關(guān)于時(shí)間、空間復(fù)雜度和穩(wěn)定性的概念放在博文后半部分裁替,建議在閱讀每種算法指標(biāo)分析前先理解這些概念项玛。為了對(duì)以下各個(gè)算法進(jìn)行方便的測(cè)試,測(cè)試主方法體如下(Java實(shí)現(xiàn)):

public class Sort {
   public static void main(String[] args) {
        int[] input = {5, 4, 7, 1, 6, 2, 8, 9, 10};
        //此處調(diào)用方法弱判,以調(diào)用冒泡排序?yàn)槔?        bubbleSort(input);
        for (int i = 1; i <= input.length; i++) {
            System.out.println(input[i - 1]);
        }
    }
}

本篇博文所有排序?qū)崿F(xiàn)均默認(rèn)從小到大襟沮。

冒泡排序(Bubble Sort)

每一次通過兩兩比較找到最大(小)的元素放在未排序序列的最后昌腰,直至有序开伏。

步驟

  1. 比較兩個(gè)相鄰的元素。如果前面比后面?zhèn)€大(性馍獭)固灵,就交換順序。
  2. 從第1個(gè)數(shù)與第2個(gè)數(shù)開始比較劫流,直到第n-1個(gè)數(shù)與第n個(gè)數(shù)結(jié)束巫玻。到最后,最大(徐艋恪)的數(shù)就"浮"在了最上面仍秤。
  3. 持續(xù)每次對(duì)前面越來越少的未排序元素重復(fù)上面的步驟,直到所有元素有序可很。

排序演示

image

源代碼(Java實(shí)現(xiàn))

public static void bubbleSort(int[] input) {
        for (int i = 1; i <= input.length; i++) {
            for (int j = 1; j <= input.length - i; j++) {
                if (input[j - 1] > input[j]) {
                    int temp = input[j - 1];
                    input[j - 1] = input[j];
                    input[j] = temp;
                }
            }
        }
}

算法指標(biāo)分析

優(yōu)化1的最好時(shí)間復(fù)雜度:當(dāng)序列有序時(shí)诗力。第一個(gè)for循環(huán)中,第2/3/11/12行語句執(zhí)行1次根穷,即頻度為1姜骡;第二個(gè)for循環(huán)中,第4屿良、5圈澈、9行語句執(zhí)行n-1次,即頻度為n-1尘惧。T(n) = 3*(n-1)+4 = 3n+1 = O(n)康栈。所以最好時(shí)間復(fù)雜度為O(n)。

最壞時(shí)間復(fù)雜度:當(dāng)序列為逆序時(shí)喷橙。第一個(gè)for循環(huán)的頻度為n啥么;第二個(gè)for循環(huán)中,j可以取 1,2,...,n-1贰逾,所以第3/4/6/7/8語句悬荣,頻度均為(1+n-1)(n-1)/2。T(n) = n(n-1)/2+n = O(n2)疙剑。所以最壞時(shí)間復(fù)雜度為O(n2)氯迂。

我們可以看出在嵌套層數(shù)多的循環(huán)語句中践叠,由最內(nèi)層語句的頻度f(n)決定時(shí)間復(fù)雜度。

平均時(shí)間復(fù)雜度:O((n+n^2)/2) = O(n^2)嚼蚀。

輔助空間:不需要額臨時(shí)的存儲(chǔ)空間來運(yùn)行算法禁灼,所以為O(1)。

穩(wěn)定性:因?yàn)榕判蚍绞绞窍噜彅?shù)比較后交換轿曙,如果序列中有相等的兩個(gè)數(shù)弄捕,待兩數(shù)相鄰時(shí),不會(huì)交換兩者的位置导帝,所以穩(wěn)定守谓。

冒泡排序的兩種優(yōu)化方式

優(yōu)化1:某一趟遍歷如果沒有元素交換,flag標(biāo)記依舊為true舟扎。說明已經(jīng)排好序了分飞,結(jié)束迭代悴务。

public static void bubbleSort2(int[] input) {
        for (int i = 1; i <= input.length; i++) {
            boolean flag = true;
            for (int j = 1; j <= input.length - i; j++) {
                if (input[j - 1] >  input[j]) {
                    int temp = input[j - 1];
                    input[j - 1] = input[j];
                    input[j] = temp;
                }
                flag = false;
            }
            if (flag)
                break;
        }
}

優(yōu)化2:記錄某次遍歷時(shí)最后發(fā)生元素交換的位置(LastExchange)睹限,這個(gè)位置之后的數(shù)據(jù)顯然已經(jīng)有序,不用再排序了讯檐。因此通過記錄最后發(fā)生元素交換的位置就可以確定下次循環(huán)的范圍羡疗。

public static void bubbleSort3(int[] input) {
        int LastExchange = input.length;
        boolean flag = true;
        for (int i = 1; i <= input.length; i++) {
            int k = LastExchange;
            for (int j = 1; j <= k - 1; j++) {
                if (input[j - 1] > input[j]) {
                    int temp = input[j - 1];
                    input[j - 1] = input[j];
                    input[j] = temp;
                }
                LastExchange = j;
                flag = false;
            }
            if (flag)
                break;
        }
}

選擇排序(Selection Sort)

每一次通過選擇找到未排序序列的最小(大)元素放在已排序序列的末尾(交換位置)别洪,直至有序叨恨。

步驟

  1. 未排序序列中找到最小(大)元素挖垛,存放到序列的起始位置痒钝。
  2. 再從剩余未排序元素中繼續(xù)找到最小(大)元素痢毒,放到已排序序列的末尾送矩。
  3. 以此類推,直到所有元素均排序完畢哪替。

排序演示

image

源代碼(Java實(shí)現(xiàn))

public static void selectionSort(int[] input) {
        for (int i = 1; i <= input.length; i++) {
            int minIndex = i - 1;
            for (int j = i; j < input.length; j++) {
                if (input[minIndex] > input[j])
                    minIndex = j;
            }
            if (minIndex != i - 1) {
                int temp = input[minIndex];
                input[minIndex] = input[i - 1];
                input[i - 1] = temp;
            }
        }
}

算法指標(biāo)分析

不管序列有序還是逆序栋荸,第二個(gè)for循環(huán)的頻度為n*(n-1)/2。所以最壞時(shí)間復(fù)雜度和最好時(shí)間復(fù)雜度均為O(n^2)凭舶。

平均時(shí)間復(fù)雜度:O(n^2)

輔助空間:不需要額臨時(shí)的存儲(chǔ)空間來運(yùn)行算法晌块,所以為O(1)。

穩(wěn)定性:不穩(wěn)定帅霜。舉例匆背,5、7身冀、5钝尸、2蜂大、9,找到最小2時(shí)蝶怔,2與5交換奶浦,此時(shí)兩個(gè)5的相對(duì)位置發(fā)生改變。

插入排序(Insertion Sort)

對(duì)于每個(gè)未排序元素踢星,在已排序序列中從后向前掃描澳叉,找到相應(yīng)位置并插入。

步驟

  1. 第1個(gè)元素視為已經(jīng)被排序
  2. 取未排序的第1個(gè)元素沐悦,在已排序序列中從后向前掃描
  3. 如果被掃描的元素大于新元素成洗,將該元素后移一位
  4. 重復(fù)步驟3,直到找到已排序的元素小于或者等于新元素的位置
  5. 將新元素插入到該位置后
  6. 重復(fù)步驟2~5
  7. 如果全部有序藏否,結(jié)束迭代

排序演示

image

源代碼(Java實(shí)現(xiàn))

public static void insertionSort(int[] input) {
        for (int i = 1; i < input.length; i++) {
            for (int j = i; j > 0; j--) {
                if (input[j] < input[j - 1]) {
                    int temp = input[j];
                    input[j] = input[j - 1];
                    input[j - 1] = temp;
                }
                else break;
            }
        }
}

算法指標(biāo)分析

最好時(shí)間復(fù)雜度:當(dāng)序列有序時(shí)瓶殃。當(dāng)?shù)谝粋€(gè)for循環(huán)運(yùn)行時(shí),在第二個(gè)for循環(huán)中副签,因?yàn)樾蛄杏行蛞4唬灾粫?huì)相鄰比較1次,就跳出循環(huán)淆储。所以兩個(gè)循環(huán)的頻度均為n-1冠场,所以最好時(shí)間復(fù)雜度均為O(n)。

最壞時(shí)間復(fù)雜度:當(dāng)序列逆序時(shí)本砰。第二個(gè)for循環(huán)的頻度為n(n-1)/2碴裙。所以最壞時(shí)間復(fù)雜度均為O(n^2)。

平均時(shí)間復(fù)雜度:O((n+n^2)/2) = O(n^2)点额。

輔助空間:不需要額臨時(shí)的存儲(chǔ)空間來運(yùn)行算法舔株,所以為O(1)。

穩(wěn)定性:因?yàn)榕判蚍绞绞莾蓛杀容^还棱,序列中如果相鄰兩個(gè)數(shù)相等载慈,不會(huì)交換兩者的位置,所以穩(wěn)定诱贿。

希爾排序(Shell Sort)

希爾排序娃肿,也稱遞減增量排序算法,實(shí)質(zhì)上是一種分組插入排序算法珠十。是插入排序的一種更高效的改進(jìn)版本料扰。
希爾排序是基于插入排序的以下兩點(diǎn)性質(zhì)而提出改進(jìn)方法的:

  • 插入排序在對(duì)幾乎已經(jīng)排好序的數(shù)據(jù)操作時(shí),效率高焙蹭,即可以達(dá)到線性排序的效率
  • 但插入排序一般來說是低效的晒杈,因?yàn)椴迦肱判蛎看沃荒軐?shù)據(jù)移動(dòng)一位

步驟

  1. 假設(shè)數(shù)組為{5, 4, 7, 1, 6, 2, 8, 9, 10},如果我們以步長為4開始進(jìn)行排序孔厉,我們可以通過將這列表放在有4列的表中來更好地描述算法拯钻,這樣他們就應(yīng)該看起來是這樣:

5, 4, 7, 1
6, 2, 8, 9
10

  1. 將數(shù)組列在一個(gè)表中并對(duì)列分別進(jìn)行插入排序

5, 2, 7, 1
6, 4, 8, 9
10

  1. 重復(fù)這過程帖努,不過每次用更長的列(步長更小,列數(shù)更少)來進(jìn)行粪般,如下步長為2拼余。

5, 2
7, 1
6, 4
8, 9
10

  1. 最后整個(gè)表就只有一列了( 再進(jìn)行插入排序)

5, 1, 6, 2, 7, 4, 8, 9, 10

源代碼(Java實(shí)現(xiàn))

public static void shellSort(int[] input) {
        int len = input.length, j;
        int gap = Math.round(len / 2);
        for (; gap > 0; gap /= 2) //步長每次就減少一倍
            for (int i = gap; i < len; i++) {
                int temp = input[i];
                for (j = i - gap; j >= 0 && temp < input[j]; j -= gap) {//列排序
                    input[j + gap] = input[j];
                    input[j] = temp;
                }
            }
}

算法指標(biāo)分析

最好時(shí)間復(fù)雜度:當(dāng)序列有序時(shí)。最好時(shí)間復(fù)雜度均為O(n^s)亩歹,1<s<2匙监,跟算法步長有關(guān)。

最壞時(shí)間復(fù)雜度:當(dāng)序列逆序時(shí)小作。最壞時(shí)間復(fù)雜度均為O(n^2)亭姥。

平均時(shí)間復(fù)雜度:O(n log n)~O(n^2)。

輔助空間:不需要額臨時(shí)的存儲(chǔ)空間來運(yùn)行算法顾稀,所以為O(1)达罗。

穩(wěn)定性:不穩(wěn)定。解釋如下:

假設(shè)静秆,序列為5,5,7,3,2粮揉,取步長為3分組為
5,5,7
3,6
3和5交換位置后,兩個(gè)5的相對(duì)順序發(fā)生改變诡宗,所以不穩(wěn)定

堆排序(HeapSort)

使用到二叉堆這種數(shù)據(jù)結(jié)構(gòu)滔蝉,二叉堆是平衡二叉樹。它具有以下性質(zhì):

  1. 父節(jié)點(diǎn)的值大于等于左右節(jié)點(diǎn)的值塔沃,為最大堆(大頂堆);父節(jié)點(diǎn)的值小于于等于左右節(jié)點(diǎn)的值阳谍,為最小堆(大頂堆)
  2. 每個(gè)父節(jié)點(diǎn)的左右節(jié)點(diǎn)都是二叉堆(大頂堆或小頂堆)

本質(zhì)上堆排序是由數(shù)組實(shí)現(xiàn)蛀柴。

步驟

  1. 調(diào)用構(gòu)造大頂堆方法,將數(shù)組構(gòu)造成大頂堆矫夯。葉子節(jié)點(diǎn)相當(dāng)于大頂堆鸽疾,假設(shè)數(shù)組下標(biāo)范圍為0~n-1,則從下標(biāo)n/2開始的元素(葉子節(jié)點(diǎn))均為大頂堆训貌。所以從下標(biāo)n/2-1開始的元素(父節(jié)點(diǎn))開始制肮,向前依次(下標(biāo)減1)構(gòu)造大頂堆。
  2. 堆排序:由于堆是用數(shù)組模擬的递沪。構(gòu)造的大頂堆相當(dāng)于在數(shù)組中無序豺鼻。因此需要將數(shù)組有序化。思想是循環(huán)將根節(jié)點(diǎn)與最后一個(gè)未排序元素交換款慨,再調(diào)用構(gòu)造大頂堆方法儒飒。循環(huán)結(jié)束后,整個(gè)數(shù)組就是有序的了檩奠。
  3. 構(gòu)造大頂堆方法:調(diào)整節(jié)點(diǎn)桩了,使得左右子節(jié)點(diǎn)小于父節(jié)點(diǎn)附帽,保證根節(jié)點(diǎn)是當(dāng)前堆中最大的元素。

排序演示:

第一次將數(shù)組構(gòu)造成大頂堆時(shí)井誉,跟此演示稍有不同蕉扮,默認(rèn)按數(shù)組順序放入二叉堆,沒有邊放邊構(gòu)造颗圣。

image

源代碼(Java實(shí)現(xiàn))

public static void heapSort(int[] input) {
        int i = input.length / 2 - 1;//最后一個(gè)非葉子節(jié)點(diǎn)
        //將數(shù)組構(gòu)造成大頂堆
        for (; i >= 0; i--)
            maxHeapify(input, i, input.length - 1);
        //堆排慢显,將大頂堆轉(zhuǎn)換成有序數(shù)組
        for (i = input.length - 1; i >= 0; i--) {
            int temp = input[0];
            input[0] = input[i];
            input[i] = temp;
            maxHeapify(input, 0, i - 1);
        }
}
 //構(gòu)造大頂堆
public static void maxHeapify(int[] input, int start, int end) {
        int child;
        int root = start;
        //父節(jié)點(diǎn)不是葉子節(jié)點(diǎn)時(shí)循環(huán);只有一個(gè)根節(jié)點(diǎn)時(shí)不再比較
        for (; root <= (end - 1) / 2 && end > 0; ) {
            child = root * 2 + 1;//調(diào)整子節(jié)點(diǎn)
            //取較大的子節(jié)點(diǎn)
            if (child + 1 <= end && input[child] < input[child + 1])
                child += 1;

            if (input[root] < input[child]) {
                //交換較小父節(jié)點(diǎn)和較大子節(jié)點(diǎn)的位置
                int temp = input[root];
                input[root] = input[child];
                input[child] = temp;
                root = child;//較大的子節(jié)點(diǎn)成為父節(jié)點(diǎn)
            } else
                break;
        }
}

算法指標(biāo)分析

最好時(shí)間復(fù)雜度:當(dāng)序列有序時(shí)欠啤。最好時(shí)間復(fù)雜度均為O(n log n)荚藻,跟算法步長有關(guān)。

最壞時(shí)間復(fù)雜度:當(dāng)序列逆序時(shí)洁段。最壞時(shí)間復(fù)雜度均為O(n log n)应狱。

平均時(shí)間復(fù)雜度:O(n log n)。

輔助空間:不需要額臨時(shí)的存儲(chǔ)空間來運(yùn)行算法祠丝,所以為O(1)疾呻。

穩(wěn)定性:不穩(wěn)定。

二分歸并排序(MergeSort)

先遞歸分解序列写半,再合并序列岸蜗。也采用了分治法的思想。

步驟

  1. 合并:合并的條件是兩個(gè)序列都有序叠蝇,當(dāng)序列中只有1個(gè)元素時(shí)我們認(rèn)為也是有序的璃岳;合并的方法是通過比較將較小元素先放入臨時(shí)數(shù)組,再將左悔捶、右序列剩余元素放入铃慷。
  2. 分解:先將源序列從中位數(shù)(中數(shù))分開為左右序列,遞歸分解左序列蜕该,中數(shù)不斷減小犁柜,直到為1。此時(shí)左堂淡、右序列中只有一個(gè)元素馋缅,通過比較將左、右序列合并為左序列后绢淀,再遞歸分解右序列(也分解到只有一個(gè)元素)萤悴。

排序演示

此圖主要思想一致,但代碼實(shí)現(xiàn)過程中更啄,6531合并完成時(shí)稚疹,8724還沒分解。

image

源代碼(Java實(shí)現(xiàn))

public static void mergeSort(int[] input) {
        merge_sort(input, 0, input.length - 1);
    }
public static void merge_sort(int[] input, int start, int end) {
        int middle;
        //當(dāng)序列中只有一個(gè)元素時(shí),結(jié)束當(dāng)前遞歸
        if (start < end) {
            middle = (start + end) / 2;//找出中位數(shù)(中數(shù))内狗,中數(shù)越來越小
            merge_sort(input, start, middle);//中數(shù)左側(cè)序列二分
            merge_sort(input, middle + 1, end);//中數(shù)右側(cè)序列二分
            merge(input, start, middle, end);//合并成源序列
        }
}
//合并成源序列
public static void merge(int[] input, int left, int middle, int right) {
        int[] temp = new int[right - left + 1];//用于存放新排好序的序列
        int i = left;//左序列的起始下標(biāo)
        int j = middle + 1;//右序列的起始下標(biāo)
        int n = 0;//temp[]數(shù)組的起始下標(biāo)
        //通過比較將較小元素先放入temp數(shù)組
        while (i <= middle && j <= right) {
            if (input[i] < input[j]) {
                temp[n] = input[i];
                i++;
            } else {
                temp[n] = input[j];
                j++;
            }
            n++;
        }
        //將第一個(gè)序列的剩余元素放入temp[]
        while (i <= middle) {
            temp[n] = input[i];
            i++;
            n++;
        }
        //將第二個(gè)序列的剩余元素放入temp[]
        while (j <= right) {
            temp[n] = input[j];
            j++;
            n++;
        }
        //將num[]中的元素復(fù)制到數(shù)組input
        for (int x = 0, y = left; x <= n && y <= right; x++, y++)
            input[y] = temp[x];
}

算法指標(biāo)分析

最好時(shí)間復(fù)雜度:當(dāng)序列有序時(shí)怪嫌。最好時(shí)間復(fù)雜度均為O(n log n)。

最壞時(shí)間復(fù)雜度:當(dāng)序列逆序時(shí)柳沙。最壞時(shí)間復(fù)雜度均為O(n log n)岩灭。

平均時(shí)間復(fù)雜度:O(n log n)。

輔助空間:需要新建額外臨時(shí)的存儲(chǔ)空間來存儲(chǔ)新排好序的序列赂鲤,每一次歸并都需要重新新建噪径,新建頻度為n,所以輔助空間為O(n)数初。

穩(wěn)定性:穩(wěn)定找爱。因?yàn)閮蓛杀容^。

快速排序(Quick Sort)

又稱劃分交換排序(partition-exchange sort)泡孩。采用了分治法的思想车摄,通常明顯比同為Ο(n log n)的其他算法更快。

步驟

  1. 將數(shù)組區(qū)塊的第n個(gè)素設(shè)為中數(shù)(中位值)仑鸥;第1個(gè)元素設(shè)為左數(shù)吮播;第n-1個(gè)元素設(shè)為右數(shù)。
  2. 左數(shù)下標(biāo)遞增眼俊,右數(shù)下標(biāo)遞減意狠。將大于等于中數(shù)的左數(shù)和小于等于中數(shù)的右數(shù)交換,直到左數(shù)和右數(shù)下標(biāo)相等疮胖。如果左(右)數(shù)大于等于中數(shù)环戈,交換位置,否則加左數(shù)下標(biāo)1获列。
  3. 對(duì)中數(shù)的左右數(shù)組區(qū)間遞歸執(zhí)行第1,2步谷市,直至各數(shù)組區(qū)間只有一個(gè)數(shù)。

排序演示

此演示的第1次選擇3作為中數(shù)击孩,與題意稍有出入,其他均相同鹏漆。

image

源代碼(Java實(shí)現(xiàn))

public static void quickSort(int[] input) {
        quick_sort(input, 0, input.length - 1);
}

private static void quick_sort(int[] input, int start, int end) {
        if (start >= end) {
            return;
        }
        int left = start, right = end - 1;
        int mid = input[end];
        while (left < right) {
            while (input[left] <= mid && left < right) {
                left++;
            }
            while (input[right] >= mid && left < right) {
                right--;
            }
            int temp = input[left];
            input[left] = input[right];
            input[right] = temp;
        }
        if (input[left] >= input[end]) {
            int temp = input[left];
            input[left] = input[end];
            input[end] = temp;
        } else
            left++;
        quick_sort(input, start, left - 1);
        quick_sort(input, left, end);
}

算法指標(biāo)分析

最好時(shí)間復(fù)雜度:當(dāng)序列有序時(shí)巩梢。所以,最好時(shí)間復(fù)雜度均為O(n log n)艺玲。

最壞時(shí)間復(fù)雜度:當(dāng)序列逆序時(shí)括蝠。所以,最壞時(shí)間復(fù)雜度均為O(n^2)饭聚。

平均時(shí)間復(fù)雜度:O(n log n)忌警。

輔助空間:需要額臨時(shí)的存儲(chǔ)空間來運(yùn)行算法,所以為O(n log n)~O(n)秒梳。

穩(wěn)定性:不穩(wěn)定法绵。

時(shí)間復(fù)雜度

時(shí)間頻度:一個(gè)算法花費(fèi)的時(shí)間與算法中語句的執(zhí)行次數(shù)成正比例箕速,哪個(gè)算法中語句執(zhí)行次數(shù)多,它花費(fèi)時(shí)間就多朋譬。一個(gè)算法中的語句執(zhí)行次數(shù)稱為語句頻度或時(shí)間頻度盐茎。記為T(n)。

時(shí)間復(fù)雜度:在剛才提到的時(shí)間頻度中徙赢,n稱為問題的規(guī)模字柠,當(dāng)n不斷變化時(shí),時(shí)間頻度T(n)也會(huì)不斷變化狡赐。但有時(shí)我們想知道它變化時(shí)呈現(xiàn)什么規(guī)律窑业。為此,我們引入時(shí)間復(fù)雜度概念枕屉。 一般情況下常柄,算法中基本操作重復(fù)執(zhí)行的次數(shù)是問題規(guī)模n的某個(gè)函數(shù),用T(n)表示搀庶,若有某個(gè)輔助函數(shù)f(n),使得當(dāng)n趨近于無窮大時(shí)拐纱,T(n)/f(n)的極限值為不等于零的常數(shù)C,則稱f(n)是T(n)的同數(shù)量級(jí)函數(shù)哥倔。記作T(n)=O(f(n)),稱O(f(n)) 為算法的漸進(jìn)時(shí)間復(fù)雜度秸架,簡稱時(shí)間復(fù)雜度。

雖然對(duì)f(n)沒有規(guī)定咆蒿,但是一般都是取盡可能簡單的函數(shù)东抹。例如,O(2n^2+n+1) = O(3n^2+n+3) = O(7n^2 + n) = O(n^2) 沃测,一般都只用O(n^2)表示就可以了缭黔。注意到大O符號(hào)里隱藏著一個(gè)常數(shù)C,所以f(n)里一般不加系數(shù)蒂破。如果把T(n)當(dāng)做一棵樹馏谨,那么O(f(n))所表達(dá)的就是樹干,只關(guān)心其中的主干附迷,其他的細(xì)枝末節(jié)全都拋棄不管惧互。

image

由上圖可見,常見的算法時(shí)間復(fù)雜度由小到大依次為:Ο(1)<Ο(log n)<Ο(n)<Ο(nlog n)<Ο(n2)<Ο(n3)<…<Ο(2^n)<Ο(n!)喇伯。

分析以下代碼的時(shí)間復(fù)雜度喊儡。

i=1;     
while (i<=n)  
  i=i*2;  

第1行語句的頻度為1
設(shè)第3行語句的時(shí)間頻度為f(n)k,2f(n) = n; -->f(n) = log n
第2行語句跟第2三行的頻度一樣稻据,為log n
以上代碼的T(n) = 2
log n+1 = O(log n)

由此可見艾猜,T(n)由最大的f(n)決定。在嵌套層數(shù)多的循環(huán)語句中,由最內(nèi)層語句的頻度f(n)決定T(n)匆赃。
注:log n = log?n = lg n淤毛;復(fù)雜度中以2為底,不是數(shù)學(xué)中以10為底炸庞。

空間復(fù)雜度

一個(gè)算法的空間復(fù)雜度(Space Complexity)定義為該算法所耗費(fèi)的存儲(chǔ)空間钱床,它也是問題規(guī)模n的函數(shù)。漸近空間復(fù)雜度也常常簡稱為空間復(fù)雜度埠居。

一個(gè)算法在計(jì)算機(jī)存儲(chǔ)器上所占用的存儲(chǔ)空間查牌,包括:

  • 存儲(chǔ)算法本身所占用的存儲(chǔ)空間
  • 算法的輸入輸出數(shù)據(jù)所占用的存儲(chǔ)空間
  • 算法在運(yùn)行過程中臨時(shí)占用的存儲(chǔ)空間

我們將算法在運(yùn)行過程中臨時(shí)占用的存儲(chǔ)空間稱為輔助空間,它隨算法的不同而異滥壕,另外兩種存儲(chǔ)空間與算法本身無關(guān)纸颜。

如當(dāng)一個(gè)算法的空間復(fù)雜度為一個(gè)常量,即不隨被處理數(shù)據(jù)量n的大小而改變時(shí)绎橘,輔助空間可表示為O(1)胁孙;當(dāng)一個(gè)算法的空間復(fù)雜度與以2為底的n的對(duì)數(shù)成正比時(shí),輔助空間可表示為O(1og?n)称鳞;當(dāng)一個(gè)算法的空間復(fù)雜度與n成線性比例關(guān)系時(shí)涮较,輔助空間可表示為O(n)。

穩(wěn)定性

在排序過程中冈止,具有相同數(shù)值的對(duì)象的相對(duì)順序被不被打亂狂票。如果可以保證不被打亂就是穩(wěn)定的,如果不能保證就是不穩(wěn)定的熙暴。

總結(jié)

根據(jù)每個(gè)排序算法關(guān)于穩(wěn)定性的指標(biāo)分析闺属,可以得出以下結(jié)論:

  1. 如果每次變換都只是交換相鄰的兩個(gè)元素,那么就是穩(wěn)定的周霉。
  2. 如果每次都有某個(gè)元素和比較遠(yuǎn)的元素的交換操作掂器,那么就是不穩(wěn)定的。

以上算法博主親測(cè)都能正確運(yùn)行俱箱。以下是上述七種算法的性能指標(biāo)分析對(duì)比情況国瓮。

排序方式 平均時(shí)間復(fù)雜度 最好時(shí)間復(fù)雜度 最壞時(shí)間復(fù)雜度 空間復(fù)雜度
(輔助空間)
穩(wěn)定性
冒泡排序 O(n^2) O(n) O(n^2) O(1) 穩(wěn)定
選擇排序 O(n^2) O(n^2) O(n^2) O(1) 不穩(wěn)定
插入排序 O(n^2) O(n) O(n^2) O(1) 穩(wěn)定
希爾排序 O(n log n)~O(n^2) O(n^s)
(0<s<1臊泌,跟步長有關(guān))
O(n^2) O(1) 不穩(wěn)定
堆排序 O(n log n) O(n log n) O(n log n) O(1) 不穩(wěn)定
二分歸并排序 O(n log n) O(n log n) O(n log n) O(n) 穩(wěn)定
快速排序 O(n log n) O(n log n) O(n^2) O(log n)~O(n) 不穩(wěn)定

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市狐史,隨后出現(xiàn)的幾起案子芋簿,更是在濱河造成了極大的恐慌,老刑警劉巖璃饱,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件与斤,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)撩穿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門磷支,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人食寡,你說我怎么就攤上這事雾狈。” “怎么了抵皱?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵善榛,是天一觀的道長。 經(jīng)常有香客問我呻畸,道長移盆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任伤为,我火速辦了婚禮咒循,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绞愚。我一直安慰自己叙甸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布位衩。 她就那樣靜靜地躺著裆蒸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蚂四。 梳的紋絲不亂的頭發(fā)上光戈,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音遂赠,去河邊找鬼久妆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛跷睦,可吹牛的內(nèi)容都是我干的筷弦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼抑诸,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼烂琴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蜕乡,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤奸绷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后层玲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體号醉,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡反症,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了畔派。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铅碍。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖线椰,靈堂內(nèi)的尸體忽然破棺而出胞谈,到底是詐尸還是另有隱情,我是刑警寧澤憨愉,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布烦绳,位于F島的核電站,受9級(jí)特大地震影響莱衩,放射性物質(zhì)發(fā)生泄漏爵嗅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一笨蚁、第九天 我趴在偏房一處隱蔽的房頂上張望睹晒。 院中可真熱鬧,春花似錦括细、人聲如沸伪很。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锉试。三九已至,卻和暖如春览濒,著一層夾襖步出監(jiān)牢的瞬間呆盖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來泰國打工贷笛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留应又,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓乏苦,卻偏偏與公主長得像株扛,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子汇荐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 概述 排序有內(nèi)部排序和外部排序洞就,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序,而外部排序是因排序的數(shù)據(jù)很大掀淘,一次不能容納全部...
    蟻前閱讀 5,183評(píng)論 0 52
  • 概述:排序有內(nèi)部排序和外部排序旬蟋,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序,而外部排序是因排序的數(shù)據(jù)很大革娄,一次不能容納全部...
    每天刷兩次牙閱讀 3,730評(píng)論 0 15
  • 該系列文章主要是記錄下自己暑假這段時(shí)間的學(xué)習(xí)筆記咖为,暑期也在實(shí)習(xí)秕狰,抽空學(xué)了很多,每個(gè)方面的知識(shí)我都會(huì)另起一篇博客去記...
    Yanci516閱讀 12,212評(píng)論 6 19
  • 風(fēng)景很美 用心去發(fā)現(xiàn)噢??
    花生花二三說閱讀 317評(píng)論 2 4
  • 1996年初次見到你架忌,之后的每逢盛夏吞彤,我都為你著迷。 科比叹放,是我們一代人的青春記憶饰恕,不管科黑還是科蜜,對(duì)你有多少愛...
    浮生幻想閱讀 262評(píng)論 0 0