排序算法(1)

本片文章是算法排序系列的第一章,也是我在平臺上的第一篇文章,希望自己能夠堅持下去,同時本部分算法學習中一定會給出Java或者scala的實現方式(心情好的話也可能是兩種語言都有),好了廢話不多說,我們切入正題,冒泡排序和選擇排序是排序算法中最爲基礎的兩種算法,個人感覺也是最爲形象的算法,屬於那種看了名字就基本知道大致思路,下面詳細介紹。

冒泡排序

你真的理解了冒泡排序嗎?冒泡排序的基本思想是依次比較相鄰兩元素,若前一元素大於後一元素則交換之,直至最後一個元素即爲最大;然後重新從首元素開始重複同樣的操作,直至倒數第二個元素即爲次大元素;…如同水中的氣泡,依次將最大或最小元素氣泡浮出水面,然後完成排序。我們先來看一段代碼:

public static void sort(int[] nums) {
    Arrays.nonBlank(nums);
    for (int i = nums.length - 1; i >= 0; i--) {
        for (int j = 1; j < i; j++) {
            if (nums[j] < nums[j - 1]) {
                int temp = nums[j];
                nums[j] = nums[j - 1];
                nums[j - 1] = temp;
            }
        }
    }
}

這是冒泡排序最爲基礎的實現,也是冒泡排序官方的代碼示例,可以看出其時間複雜度爲O(n^2),且是穩定排序,但是如果現在待排序數據已經有序,那麼經過這種實現方式也是要進行雙層循環的,那麼有沒有對冒泡排序算法的改進,讓已經有序的序列能夠避免無用的循環呢?答案是有的,可以添加一個元素交換的標記位,如果在遍歷了一遍數組之後發現沒有發生元素交換,那麼可以判定數組就是有序的,這時無需進行後續循環就可得到有序數組,具體代碼實現如下:

public static void sort(int[] nums) {
    Arrays.nonBlank(nums);
    boolean isSort = true;
    for (int i = nums.length - 1; isSort && i >= 0; i--) {
        isSort = false;
        for (int j = 1; j < i; j++) {
            if (nums[j] < nums[j - 1]) {
                int temp = nums[j];
                nums[j] = nums[j - 1];
                nums[j - 1] = temp;
                isSort = true;
            }
        }
    }
}

極端情況下兩種方式的執行情況如何呢?初始化一個10w元素的數組,兩種算法的執行時間如下:

改進前算法用時:1397ms,改進後算法用時:1ms

選擇排序

選擇排序也是基礎排序算法之一,由其名字就可知從數組中選擇最小或者最大的元素放在首位,再選擇次小或者次大的元素放在首位之後,以此類推,這樣就可以完成數據的排序。當然這只是最直觀的理解,下面我們給出基本步驟,首先初始化最小元素索引值爲首元素,依次遍歷待排序數列,若遇到小於該最小索引位置處的元素則刷新最小索引爲該較小元素的位置,直至遇到尾元素,結束第一次遍歷,且將最小索引處元素與首元素交換;然後,初始化次小索引值爲下一個待排序數列元素位置,同樣的操作,可得到數列第二個元素即爲次小元素;循環完畢,即完成排序,具體代碼如下。

public static void sort(int[] nums) {
    Arrays.nonEmpty(nums);
    for (int i = 0; i < nums.length; i++) {
        int minIndex = i;
        for (int j = i + 1; j < end; ++j) {
            if (arr[j] < arr[minIndex]) minIndex = j;
        }
        if (minIndex != i) {
 		   int temp = nums[j];
            nums[j] = nums[j - 1];
            nums[j - 1] = temp;           
        }
    }
}

選擇排序的時間複雜度爲O(n^2),並且其屬於不穩定排序,選擇排序由於要在全局找出最小值(或最大值),所以優化的方法較少,基本就是全局遍歷找出最小(或最大),然後交換。

在算法賦值實現中可以採集位運算來進行賦值,具體代碼如下:

x = x^y; y = x^y; x = x^y; (不要問我爲什麼這樣做,最起碼看着就很高級是不是)

總結

兩個最基本的排序算法沒有什麼好說的,想在這聊聊穩定排序和非穩定排序,穩定排序不會破壞數組的原始的元素順序,比如排序過程中不同位置存在多個相同值,那麼穩定排序能夠保證其原始順序不變,而不穩定排序則不能保證這種原始順序,那麼這種原始順序有什麼用,坦白講,單一數值排序並沒有什麼用,複雜對象排序中,如果不在意初始順序的情況,也沒有什麼用,最後就只剩下一種情況,就是多類數值字段的複雜對象在意初始對象順序,並且在按某個字段排序後還希望排序字段相同數值對應的元素能夠保留原始順序,這樣的場景下必須要選擇穩定的排序算法,完畢。

吾之所向,一往無前,越挫越勇,再接再厲 ——孫中山

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章