1. 程式人生 > >八大排序演算法JAVA實現(時間複雜度O(n-logn)篇)

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

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

一、歸併排序

  •  原理:把兩個有序數列合併為一個有序數列。需遞迴實現。
  •  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 }

二、快速排序

  •  原理:每一次將一個數放在一個左邊的數全部比它小,且右邊的數全部比它大的位置,然後遞迴呼叫函式,將其左右序列排好。這邊有一個比較好理解的做法:在陣列的左邊維護一個小於區間,在遍歷的時候,發現比當前數小的數字的時候,將,擴增小於區間,並其放到小於區間內,結束後將當前數填充在小於區間後即可。
  • 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     }        
  •  變形應用:三色排序練習題

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

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

三、堆排序

  • 原理:維護一個大根堆(小根堆同理),即維護一棵二叉樹,該數子節點永遠比父節點小。每次在大根堆中取出根,根為此時待排序列最大值,放在待排序列最後,然後調整大根堆,重複上訴過程即可。
  • 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的小根堆,每次調整完這個小根堆後,最小值就會出現在第一位,此時移除第一位,新增後一位數進來,繼續調整這個小根堆即可。可以想象為一個從前往後移動的滑動視窗,滑動視窗中是一個小根堆。

四、希爾排序

  • 原理:變形後的插入排序,每個數只與它前面固定步長的倍數的位置進行比對。如:步長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;
    }

相關推薦

八大排序演算法JAVA實現時間複雜O(n-logn)

本文講述時間複雜度為n*logn的排序演算法:歸併排序、快速排序、堆排序以及希爾排序的原理、Java實現以及變形應用。 一、歸併排序  原理:把兩個有序數列合併為一個有序數列。需遞迴實現。  Java實現: 1 public int[] mergeSort(in

八大排序演算法JAVA實現時間複雜O(n-n)

本文主要描述3個時間複雜度為n2的排序演算法:氣泡排序、選擇排序、插入排序。 1.氣泡排序:由陣列頭部開始,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。每次交換完成後,當前陣列最大值就會被放在最後。 1 public int[] bubbleSort

C語言八大排序演算法(包括穩定性、時間複雜收藏)

C語言八大排序演算法 概述 排序有內部排序和外部排序,內部排序是資料記錄在記憶體中進行排序,而外部排序是因排序的資料很大,一次不能容納全部的排序記錄,在排序過程中需要訪問外存。我們這裡說說八大排序就是內部排序。 當n較大,則應採用時間複雜度為O(nlog2n)的排序方法:快速排序、堆排

排序JAVA實現時間複雜分析

堆排序是一個比較常用的排序方式,下面是其JAVA的實現: 1. 建堆 // 對輸入的陣列進行建堆的操作 private static void buildMaxHeap(int[] array, int length) { // 遍歷所有

尋找主元素演算法時間複雜O(N),C#)

主元素問題:大小為N的陣列A,其主要元素是一個出現次數超過N/2的元素。 最近在學習演算法,書上發現這樣一道題,並且提供了一種遞迴演算法的概要,但是感覺不是特別好(遞迴判斷(時間複雜度大於O(N)了),還要對N的奇偶做出判斷以及使用附加陣列B),網上看了一下有一個SEO排行最靠前的(不說名字了,

Morris遍歷詳解——二叉樹先序中序後序遍歷 時間複雜O(N),空間複雜O(1)

Morris二叉樹遍歷: 來到當前的節點:Cur 如果Cur無左孩子,Cur向右移動 (Cur = Cur.right) 如果Cur有左孩子,找到Cur左子樹上最右的節點,記為 mostright

1134 最長遞增子序列時間複雜O(n*log(n)

基準時間限制:1 秒 空間限制:131072 KB 分值: 0 難度:基礎題 Description 給出長度為N的陣列,找出這個陣列的最長遞增子序列。(遞增子序列是指,子序列的元素是遞增的) 例如:5 1 6 8 2 4 5 10,最長遞增

【資料結構與演算法-java實現】二 複雜分析:最好、最壞、平均、均攤時間複雜的概念

上一篇文章學習了:如何分析、統計演算法的執行效率和資源消耗? 點選連結檢視上一篇文章:複雜度分析上 今天的文章學習以下內容: 最好情況時間複雜度 最壞情況時間複雜度 平均情況時間複雜度 均攤時間複雜度 1、最好與最壞情況時間複雜度 我們首先

連結串列排序演算法java實現連結串列的快速排序、插入排序、歸併排序

難易程度:★★ 重要性:★★★      連結串列的排序相對陣列的排序更為複雜些,也是考察求職者是否真正理解了排序演算法(而不是“死記硬背”) 連結串列的插入排序 public class LinkedInsertSort { static cla

基礎排序演算法 java 實現冒泡、選擇、插入、快排、歸併、堆排

package demo; import java.util.Arrays; public class SortUtil { private static void printArr(int[] arr) { System.out.println

有1,2...一直到n的無序陣列,求排序演算法,並且要求時間複雜On,時間複雜O1

提示:用陣列值作為下標 分析:        對於一般陣列的排序顯然 O(n) 是無法完成的。       既然題目這樣要求,肯定原先的陣列有一定的規律,讓人們去尋找一種機會。 例如:原始陣列:           a = [ 10, 6,9, 5,2

常見排序演算法及對應的時間複雜和空間複雜

轉載請註明出處: 排序演算法經過了很長時間的演變,產生了很多種不同的方法。對於初學者來說,對它們進行整理便於理解記憶顯得很重要。每種演算法都有它特定的使用場合,很難通用。因此,我們很有必要對所有常見的排序演算法進行歸納。 排序大的分類可以分為兩種:內

BFPRT演算法時間複雜O(n)求第k小的數字分治演算法+快排

去年寫了一篇《分治演算法 求第 k k k小元素

並行排序演算法——時間複雜O(n)的排序

最近老師講了並行的排序演算法,讓我對這個原來不是很瞭解的排序演算法產生了濃厚的興趣。並行排序方法,是指採用平行計算的方法對一組資料進行排序,理論上是在類似內排序的環境下,採用多核並行的方法讓時間降低,排序的複雜度最好的情況下能降低至O(n)左右。 排序的實質

一個時間複雜O(n),空間複雜O(1)的排序演算法

其實就是利用Hash的思想,開闢一個固定長度的hash陣列用於標記待排序陣列的資料元素是否出現過。由於固定長度的hash陣列,所以空間複雜度與待排序陣列資料規模n沒有關係,也就是說空間複雜度為O(1)。

計數排序,傳說中時間複雜O(n+k)的排序演算法

基本思想 假設數序列中小於元素a的個數為n,則直接把a放到第n+1個位置上。當存在幾個相同的元素時要做適當的調整,因為不能把所有的元素放到同一個位置上。計數排序假設輸入的元素都是0到k之間的整數。 回到頂部 參考程式碼 #include &

找出大陣列array中第k大的元素要求時間複雜O(n)

具體的程式碼實現:import java.util.Stack; /** * @author wuwh * @date createTime:2016年3月6日 上午12:23:14 */ public class KthBiggest { public static

最大子序列的和演算法-時間複雜O(n)

#include<iostream> using namespace std; int MaxSubseqSum(int ar[],int n){ int ThisSum=0,MaxSu

Manacher演算法,最長迴文串,時間複雜O(n)

最長迴文子串 問題 對於一個字串,請設計一個高效演算法,計算其中最長迴文子串的長度。 給定字串A以及它的長度n,請返回最長迴文子串的長度。 測試樣例: “abc1234321ab”,12 返回:7 中心擴充套件到Manache

php多維陣列的去重針對任意的鍵值進行去重--二維陣列的唯一--時間複雜~O(n)

以二維陣列為例,來說明針對任意鍵值的去重,時間複雜度為~O(n),只用一個foreach迴圈: <?php $arr = array( '0'=>array(