八大排序算法JAVA實現(時間複雜度O(n*logn)篇)

本文講述時間複雜度爲n*logn的排序算法:歸併排序、快速排序、堆排序以及希爾排序的原理、Java實現以及變形應用。算法

1、歸併排序

  •  原理:把兩個有序數列合併爲一個有序數列。需遞歸實現。
  •  Java實現:
 1     public int[] mergeSort(int[] a, int n)
 2     {
 3         return doMergeSort(a, n, 0, n - 1);
 4     }
 5         public int[] doMergeSort(int[] a, int n, int start, int end)
 6     {
 7         int[] res = new int[n];
 8         if (n <= 1)
 9         {
10             res[0] = a[start];
11             return res;
12         }
13         // n>=2時,對其左右數組進行處理
14         int half = n / 2;
15         int leftEnd = start + half - 1;
16         int rightStart = leftEnd + 1;
17         //遞歸調用本函數,獲取有序的左數組以及右數組
18         int[] left = doMergeSort(a, half, start, leftEnd);
19         int[] right = doMergeSort(a, n - half, rightStart, end);
20         // 將左右序列合併
21         int k = 0, i = 0, j = 0;
22         while (i < half && j < n - half)
23         {//由前日後比較兩個序列,取較小值填充到res中,取值後該序列日後移動取下一個值比較
24             if (left[i] <= right[j])
25             {
26                 res[k++] = left[i++];
27             }
28             else
29             {
30                 res[k++] = right[j++];
31             }
32         }
33         // 剩餘的直接放入
34         while (i < half)
35         {
36             res[k++] = left[i++];
37         }
38         while (j < n - half)
39         {
40             res[k++] = right[j++];
41         }
42         return res;
43     }            

2、快速排序

  •  原理:每一次將一個數放在一個左邊的數所有比它小,且右邊的數所有比它大的位置,而後遞歸調用函數,將其左右序列排好。這邊有一個比較好理解的作法:在數組的左邊維護一個小於區間,在遍歷的時候,發現比當前數小的數字的時候,將,擴增小於區間,並其放到小於區間內,結束後將當前數填充在小於區間後便可。
  • Java實現:
 1     public int[] quickSort(int[] a, int n)
 2     {
 3         doQuickSort(a, n, 0, n - 1);
 4         return a;
 5     }
 6     public void doQuickSort(int[] a, int n, int start, int end)
 7     {
 8         if (n > 1)
 9         {
10             int current = a[end];
11             int minLen = 0;// 小於區間的長度
12             int i = start;
13             for (; i < end; i++)
14             {
15                 if (a[i] < current)
16                 {//發現比當前數小的數,擴充小於區間
17                     int temp = a[start + minLen];
18                     a[start + minLen] = a[i];
19                     a[i] = temp;
20                     minLen++;
21                 }
22             }
23             a[end] = a[start + minLen];
24             a[start + minLen] = current;
25             //當前位置已經肯定,排左右序列
26             doQuickSort(a, minLen, start, start + minLen - 1);
27             doQuickSort(a, n - minLen - 1, start + minLen + 1, end);
28         }
29     }        
  •  變形應用:三色排序練習題shell

有一個只由0,1,2三種元素構成的整數數組,請使用交換、原地排序而不是使用計數進行排序。給定一個只含0,1,2的整數數組A及它的大小,請返回排序後的數組。保證數組大小小於等於500。
測試樣例:
[0,1,1,0,2,2],6
返回:[0,0,1,1,2,2]

解析:運用快排的原理。用數字1來處理,在數組左右各維護一個小於區間和大於區間。

 

3、堆排序

  • 原理:維護一個大根堆(小根堆同理),即維護一棵二叉樹,該數子節點永遠比父節點小。每次在大根堆中取出根,根爲此時待排序列最大值,放在待排序列最後,而後調整大根堆,重複上訴過程便可。
  • Java實現:博主不太會插圖,關於大小根堆的調整細節可自行百度。原理總結來講是從最後一個非葉子節點開始,往前調整。設當前調整的非葉子節點爲n,選舉n,n的左,n的右三個節點的最大值做爲父節點。且每次調整了靠前的非葉子節點的值後,可能會破壞下面的數的大根堆規則,須要再次調整。嗯我以爲我並無講清楚,百度看看圖就好。
    public int[] heapSort(int[] a, int n)
    {
        for (int len = n; len > 0; len--)
        {// len爲構建的堆的大小
            for (int i = len / 2 - 1; i >= 0; i--)
            {// 從後往前遍歷非葉子節點
                while (2 * i + 1 < len)
                {
                    int j = 2 * i + 1;// 左節點序號
                    if (j + 1 < len && a[j] < a[j + 1])
                    {
                        j++;
                    }
                    if (a[i] < a[j])
                    {
                        int temp = a[j];
                        a[j] = a[i];
                        a[i] = temp;
                        i = j;
                    }
                    else
                    {
                        break;
                    }
                }
            }
            int temp = a[len - 1];
            a[len - 1] = a[0];
            a[0] = temp;
        }
        return a;
    }
  • 變形應用:常規應用如在1000+個數中找出最大的10個數之類的。

已知一個幾乎有序的數組,幾乎有序是指,若是把數組排好順序的話,每一個元素移動的距離能夠不超過k,而且k相對於數組來講比較小。請選擇一個合適的排序算法針對這個數據進行排序。 給定一個int數組A,同時給定A的大小n和題意中的k,請返回排序後的數組。 數組

測試樣例: [2,1,4,3,6,5,8,7,10,9],10,2 函數

返回:[1,2,3,4,5,6,7,8,9,10] 測試

解析:維護一個大小爲k的小根堆,每次調整完這個小根堆後,最小值就會出如今第一位,此時移除第一位,添加後一位數進來,繼續調整這個小根堆便可。能夠想象爲一個從前日後移動的滑動窗口,滑動窗口中是一個小根堆。ui

4、希爾排序

  • 原理:變形後的插入排序,每一個數只與它前面固定步長的倍數的位置進行比對。如:步長step,當前數與它前面step,step*2,step*3....位置進行比較,插入到合適的位置。
  • Java實現:
    public int[] shellSort(int[] a, int n)
    {
        // 步長選擇
        for (int k = 1, step = 10; step > 1; k++)
        {
            step = n / (2 * k);
            for (int i = step; i < n; i++)
            {
                if (a[i] < a[i - step])
                {
                    int temp = a[i];
                    a[i] = a[i - step];
                    a[i - step] = temp;
                    int pre = i - step;
                    while (pre - step > 0)
                    {
                        if (a[pre] < a[pre - step])
                        {
                            temp = a[pre];
                            a[pre] = a[pre - step];
                            a[pre - step] = temp;
                            pre -= step;
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
        }
        return a;
    }
相關文章
相關標籤/搜索