排序算法

1. 插入排序

  • 思想: 假設左邊的已經(jīng)排好序惦费,要加入的數(shù)值需要從右邊開始逐個比較哮塞。如果小于下一個要比較的值arr[j-1]南蹂,那么交換arr[j-1]到后面一個位置。如果大于或等于(即不小于)下一個要比較的值arr[j-1]囱井,那么要插入的值位置應該在arr[j]驹尼。

  • java實現(xiàn)

package Sort;

import java.util.Arrays;

public class InsertSort {

    public static void main(String[] args) {
        int[] arr= {5,3,8,6,4};
        ToInsertSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    
    public static void ToInsertSort(int[] arr) {
        if(arr==null || arr.length==0)
            return;
        
        for(int i=1;i<arr.length;i++) { //假設最左邊的已經(jīng)排序好
            int temp=arr[i];            //這個位置可能被占用
            
        
            int j=i;
            while(j>0&&arr[j-1]>temp) {
                arr[j]=arr[j-1];
                j--;
            }
            
            arr[j]=temp;
        }
    }

}
  • 復雜度
  1. 時間上,最壞庞呕,1+2+ ... +(n-1)=n*(n-1)/2新翎;最好,n
  2. 空間上住练,n

2. 選擇排序

  • 思想:插入排序的改進地啰。考慮到插入排序在序列基本有序的條件下讲逛,效率更高亏吝。選擇增量序列,進行k趟排序盏混。
package Sort;

import java.util.Arrays;

public class ShellSort {

    public static void main(String[] args) {
        int[] arr= {5,3,8,6,4,9,10,5,6};
        shellSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    
    public static void shellSort(int[] arr) {
        if(arr==null || arr.length==0)
            return;
        
        int d=arr.length/2;
        for(;d>=1;d=d/2) {
            shellInsert(arr,d);
        }
    }
    
    private static void shellInsert(int[] arr,int d) {
        //進行插入排序
        for(int i=d;i<arr.length;i++) {    //假設d位置之前的已經(jīng)排好序
            int temp=arr[i];
            int j=i;
            while(j>d-1&&arr[j-d]>temp) {
                arr[j]=arr[j-d];
                j-=d;  //競爭j-d  -->j-d位置
            }
        arr[j]=temp;
        }
    }

}
  • 復雜度
  1. 時間上蔚鸥,最壞惜论,不好算,是o(n^2 )止喷;最好馆类,log(n)*n;平均弹谁,n^1.3
  2. 空間上乾巧,n

3. 選擇排序

  • 思想:選擇出最小值的下標,進行交換预愤。
package Sort;

import java.util.Arrays;

public class SelectSort {

    public static void main(String[] args) {
        int[] arr= {5,3,8,6,4,9,10,5,6};
        selectSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    
    public static void selectSort(int[] arr) {
        if(arr==null || arr.length==0)
            return;
        
        for(int i=0;i<arr.length-1;i++) {
            int minindex=i;
            for(int j=i+1;j<arr.length;j++) {
                if(arr[minindex]>arr[j])
                    minindex=j;
            }
            
            if(minindex!=i)
                swap(arr,minindex,i);
        }
    }
    
    private static void swap(int[] arr,int i,int j) {
        int temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    } 
}
  • 復雜度
  1. 時間上沟于,最壞和最好都是1+2+3+ ... +n-1=n(n-1)/2
  2. 空間上,n鳖粟。輔助空間o(1)

4. 冒泡排序

  • 思想:比較相鄰的兩個元素社裆,仍后根據(jù)結果決定是否交換位置。比選擇排序要差向图,交換次數(shù)太多。不過有一點優(yōu)于選擇排序:可以根據(jù)某個指標判斷是否提前完成排序标沪。
package Sort;

import java.util.Arrays;

public class BubbleSort {

    public static void main(String[] args) {
        int[] arr= {5,3,8,6,4,9,10,5,6};
        bubbleSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    
    public static void bubbleSort(int[] arr) {
        if(arr==null || arr.length==0)
            return;
        
        int flag=0;
        for(int i=0;i<arr.length-1;i++) {
            if(flag==1)
                break;
            
            flag=1;
            for(int j=arr.length-1;j>i;j--) {
                if(arr[j]<arr[j-1]) {
                    swap(arr,j,j-1);
                    flag=0;
                }
            }
        }
    }
    
    private static void swap(int[] arr,int i,int j) {
        int temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    } 

}
  • 復雜度
  1. 時間上榄攀,最壞o(n^2) ,最好o(n)金句。
  2. 空間上檩赢,n。輔助空間o(1)

5. 歸并排序

  • 思想:分而治之违寞,后合并贞瞒。分到只有一個數(shù)為止,然后合并趁曼。
package Sort;

import java.util.Arrays;

public class MergeSort {

    public static void main(String[] args) {
        int[] arr= {5,3,8,6,4,9,10,5,6};
        mergeSort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
    
    public static void mergeSort(int[] arr,int left,int right) {
        if(arr==null || arr.length==0)
            return;
        
        if(left>=right)
            return;
        
        int mid=(left+right)/2;
        mergeSort(arr,left,mid);
        mergeSort(arr,mid+1,right);
        merge(arr,left,mid,right);
    }
    
    private static void merge(int[] arr,int left,int mid,int right) {
        int[] temp=new int[right-left+1];
        int i=left;
        int j=mid+1;
        int k=0;
        while(i<=mid&&j<=right) {
            if(arr[i]<arr[j]) 
                temp[k++]=arr[i++];
            else
                temp[k++]=arr[j++];
        }
        
        while(i<=mid)
            temp[k++]=arr[i++];
        while(j<=right)
            temp[k++]=arr[j++];
        
        for(int p=0;p<temp.length;p++)
            arr[left+p]=temp[p];
    }
}
  • 復雜度
  1. 時間上军浆,nlog(n)。
  2. 空間上挡闰,n+n乒融。輔助空間o(n)

6. 快速排序

  • 思想:分而治之。每次確定出來一個pivot(基準)摄悯。它左邊的數(shù)都比pivot小赞季,右邊都大。這樣pivot的位置就確定了奢驯。遞歸下去申钩。有歸并的味道。不過瘪阁,歸并是后期發(fā)力撒遣《鲜ⅲ快速一開始就會確定一個位置。
package Sort;

import java.util.Arrays;

public class QuickSort {

    public static void main(String[] args) {
        int[] arr= {5,3,8,6,4,9,10,5,6};
        quickSort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
    
    public static void quickSort(int[] arr,int left,int right) {
        if(arr==null || arr.length==0)
            return;
        
        if(left>=right)
            return;
        
        int pivot=partition(arr,left,right);
        quickSort(arr,left,pivot-1);
        quickSort(arr,pivot+1,right);
    }
    
    private static int partition(int[] arr,int left,int right) {
        int pivot=left;
        int pivotKey=arr[left];
        
        while(left<right) {
            while(left<right&&arr[right]>=pivotKey)
                right--;
            while(left<right&&arr[left]<=pivotKey)
                left++;
            
            swap(arr,left,right);
        }
        
        if(left!=pivot)
            swap(arr,left,pivot);
        
        return left;
    }
    
    private static void swap(int[] arr,int i,int j) {
        int temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    } 
}
  • 復雜度
  1. 時間上愉舔,平均nlog(n)钢猛。
  2. 空間上,n轩缤。輔助空間o(1)

7. 堆排序

  • 思想:首先命迈,調(diào)整數(shù)組到滿足堆性質(zhì)。大頂堆火的,即數(shù)組第1個數(shù)最大壶愤。然后交換首末數(shù)。這樣最后面的數(shù)最大馏鹤。調(diào)整堆征椒。
package Sort;

import java.util.Arrays;

public class HeapSort {

    public static void main(String[] args) {
        int[] arr= {5,3,8,6,4,9,10,5,6};
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    
    public static void heapSort(int[] arr) {
        for(int i=arr.length/2-1;i>=0;i--) {   //下標為arr.length/2-1,才開始有子葉
            heapAdjust(arr,i,arr.length-1);
        }
        
        for(int i=arr.length-1;i>0;i--) {
            int temp=arr[0];
            arr[0]=arr[i];
            arr[i]=temp;
            
            heapAdjust(arr,0,i-1);
        }
        
    }
    
    private static void heapAdjust(int[] arr,int start,int end) {
        int temp=arr[start];
        int i=2*start+1;
        while(i<=end) {  //子節(jié)點是2*i+1  2*i+1
            if(i<end&&arr[i]<arr[i+1])
                i++;
            
            if(temp>=arr[i])    //滿足堆性質(zhì)
                break;
            
            arr[start]=arr[i];
            start=i;            //開啟下一輪,確定下標i位置是否滿足性質(zhì)
            i=2*start+1;
        }
        arr[start]=temp;
    }

}
  • 復雜度
  1. 時間上湃累,o(nlog(n))勃救。
  2. 空間上,n治力。輔助空間o(1)

8. 基數(shù)排序

  • 思想:借助多關鍵字排序思想對單邏輯關鍵字進行排序的方法蒙秒。如果對數(shù)字進行排序,那么個位宵统、十位晕讲、百位就是不同優(yōu)先級的關鍵字,如果要進行升序排序马澈,那么個位瓢省、十位、百位優(yōu)先級一次增加痊班∏诨椋基數(shù)排序是通過多次的收分配和收集來實現(xiàn)的,關鍵字優(yōu)先級低的先進行分配和收集辩块。
package Sort;
import java.util.*;

public class RadixSort {

    public static void main(String[] args) {
        int max=100;
        int min=1;
        int[] arr = new int[10];
        Random random = new Random(47);
        for (int i=0; i<10; i++) {
            int s = random.nextInt(max)%(max-min+1) + min;
            arr[i]=s;
            //System.out.println(s);
        }
        //int[] arr= {5,3,8,6,4,9,10,5,6,12,123};
        radixSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    
    public static void radixSort(int[] arr) {
        if(arr==null || arr.length==0)
            return;
        
        int arrMax=getMax(arr);
        int maxBit = (arrMax+"").length();
        for(int i=1;i<=maxBit;i++) {
            List<List<Integer>> buf=distribute(arr,i,maxBit);
            collect(arr,buf);
        }
    }
    
    public static void collect(int[] arr,List<List<Integer>> buf) {
        int k=0;
        for(List<Integer> bucket:buf) {
            for(int ele:bucket) {
                arr[k++]=ele;
            }
        }
    }
    
    public static List<List<Integer>> distribute(int[] arr,int bit,int maxBit){
        List<List<Integer>> buf = new ArrayList<List<Integer>>();
        for(int i=1;i<=10;i++)
            buf.add(new LinkedList<Integer>()); 
        
        for(int i=0; i<arr.length; i++) {
            buf.get(getNBit(arr[i], bit)).add(arr[i]);
        }
        return buf;
    }
    
    public static int getNBit(int x, int n) {
        String sx = x + "";
        if(sx.length() < n)
            return 0;
        else{
            return sx.charAt(sx.length()-n)-'0';
        }
    }

    public static int getMax(int[] arr) {
         int max=arr[0];
         for(int i=1;i<arr.length;i++){
              if(arr[i]>max){
                 max=arr[i];
              }
         }
         
        return max;
    }
}
  • 復雜度
  1. 時間上蛔六,o(d(n+rd))
  2. 空間上,n+rd废亭。輔助空間o(rd)

總結(來源“算法愛好者”)

在前面的介紹和分析中我們提到了冒泡排序国章、選擇排序、插入排序三種簡單的排序及其變種快速排序豆村、堆排序液兽、希爾排序三種比較高效的排序。后面我們又分析了基于分治遞歸思想的歸并排序還有計數(shù)排序、桶排序四啰、基數(shù)排序三種線性排序宁玫。我們可以知道排序算法要么簡單有效,要么是利用簡單排序的特點加以改進柑晒,要么是以空間換取時間在特定情況下的高效排序欧瘪。但是這些排序方法都不是固定不變的,需要結合具體的需求和場景來選擇甚至組合使用匙赞。才能達到高效穩(wěn)定的目的佛掖。沒有最好的排序,只有最適合的排序涌庭。

下面就總結一下排序算法的各自的使用場景和適用場合芥被。


  1. 從平均時間來看,快速排序是效率最高的坐榆,但快速排序在最壞情況下的時間性能不如堆排序和歸并排序拴魄。而后者相比較的結果是,在n較大時歸并排序使用時間較少席镀,但使用輔助空間較多匹中。

  2. 上面說的簡單排序包括除希爾排序之外的所有冒泡排序、插入排序愉昆、簡單選擇排序职员。其中直接插入排序最簡單,但序列基本有序或者n較小時跛溉,直接插入排序是好的方法,因此常將它和其他的排序方法扮授,如快速排序芳室、歸并排序等結合在一起使用。

  3. 基數(shù)排序的時間復雜度也可以寫成O(d*n)刹勃。因此它最使用于n值很大而關鍵字較小的的序列堪侯。若關鍵字也很大,而序列中大多數(shù)記錄的最高關鍵字均不同荔仁,則亦可先按最高關鍵字不同伍宦,將序列分成若干小的子序列,而后進行直接插入排序乏梁。

  4. 從方法的穩(wěn)定性來比較次洼,基數(shù)排序是穩(wěn)定的內(nèi)排方法,所有時間復雜度為O(n^2)的簡單排序也是穩(wěn)定的遇骑。但是快速排序卖毁、堆排序、希爾排序等時間性能較好的排序方法都是不穩(wěn)定的落萎。穩(wěn)定性需要根據(jù)具體需求選擇亥啦。

  5. 上面的算法實現(xiàn)大多數(shù)是使用線性存儲結構炭剪,像插入排序這種算法用鏈表實現(xiàn)更好,省去了移動元素的時間翔脱。具體的存儲結構在具體的實現(xiàn)版本中也是不同的奴拦。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市届吁,隨后出現(xiàn)的幾起案子错妖,更是在濱河造成了極大的恐慌,老刑警劉巖瓷产,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件站玄,死亡現(xiàn)場離奇詭異,居然都是意外死亡濒旦,警方通過查閱死者的電腦和手機株旷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尔邓,“玉大人晾剖,你說我怎么就攤上這事√菟裕” “怎么了齿尽?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長灯节。 經(jīng)常有香客問我循头,道長,這世上最難降的妖魔是什么炎疆? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任卡骂,我火速辦了婚禮,結果婚禮上形入,老公的妹妹穿的比我還像新娘全跨。我一直安慰自己,他們只是感情好亿遂,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布浓若。 她就那樣靜靜地躺著,像睡著了一般蛇数。 火紅的嫁衣襯著肌膚如雪挪钓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天苞慢,我揣著相機與錄音诵原,去河邊找鬼。 笑死,一個胖子當著我的面吹牛绍赛,可吹牛的內(nèi)容都是我干的蔓纠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吗蚌,長吁一口氣:“原來是場噩夢啊……” “哼腿倚!你這毒婦竟也來了?” 一聲冷哼從身側響起蚯妇,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤敷燎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后箩言,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體硬贯,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年陨收,在試婚紗的時候發(fā)現(xiàn)自己被綠了饭豹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡务漩,死狀恐怖拄衰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情饵骨,我是刑警寧澤翘悉,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站居触,受9級特大地震影響妖混,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜轮洋,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一源葫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧砖瞧,春花似錦、人聲如沸嚷狞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽床未。三九已至竭翠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間薇搁,已是汗流浹背斋扰。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人传货。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓屎鳍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親问裕。 傳聞我的和親對象是個殘疾皇子逮壁,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

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

  • 概述 排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進行排序粮宛,而外部排序是因排序的數(shù)據(jù)很大窥淆,一次不能容納全部...
    蟻前閱讀 5,183評論 0 52
  • 概述:排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進行排序巍杈,而外部排序是因排序的數(shù)據(jù)很大忧饭,一次不能容納全部...
    每天刷兩次牙閱讀 3,730評論 0 15
  • 概述排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進行排序筷畦,而外部排序是因排序的數(shù)據(jù)很大词裤,一次不能容納全部的...
    Luc_閱讀 2,270評論 0 35
  • 那臺被摔得體無完膚的手機現(xiàn)如今已經(jīng)不再驕傲亚斋,卻仍舊只能在那冰冷的地板上發(fā)呆失神,茍延殘喘攘滩,而它的主人李大衛(wèi)也跟著垂...
    小四不四閱讀 277評論 4 2
  • 兒子今年上六年級了帅刊。 其實一直以來對學習沒有那么喜歡,對于作業(yè)一直比較排斥漂问,多少都會磨蹭一下赖瞒,經(jīng)常會因為摩蹭而耽誤...
    晴溪閱讀 880評論 0 0