歸併排序採用的是分治的思想,先把數據集和分成兩個子數據集合進行歸併排序,然後將已經排好序的兩個子序列合併成一個有序的數據集合,歸併排序是一個非常穩定的排序算法。
基本概念:
歸併排序具體算法描述如下(遞歸版本):
1、Divide: 把長度爲n的輸入序列分成兩個長度爲n/2的子序列。
2、Conquer: 對這兩個子序列分別採用歸併排序。
3、Combine: 將兩個排序好的子序列合併成一個最終的排序序列。
框架分析:
1.歸併排序算法核心是已排序的兩個子序列合併的步驟
2.分爲兩個子序列的操作有log(n)次就到最小序列了
3.合併操作和合並完成後的序列長度n有關
在合併步驟中,會創建一個大小和兩個子序列打大小和一樣的數組空間,排序過程中會有3個循環
體,不過這些循環體都是並列的,沒有嵌套循環,在最外面也有個循環,這個循環大小爲新建數組空間大小
。三個內循環,第一個循環就是比較兩個子序列 元素的大小,選出符合條件的數知道其中一個子序列數據
比較完了,再執行接下來的循環體:將另一個還有數據的子序列的數插入新建的臨時空間中去,這樣就得到了一個排序完全的數據集合。
算法穩定性:歸併排序是一個非常穩定的排序算法。
代碼實現:
/*
* mergesort 歸併排序
* @param true 爲增序排列,相反爲降序排列
* 時間複雜度爲O(nlog(n))
*/
public static void mergeSort(boolean flag){
apart(array , 0 , array.length-1 , flag);
}
private static void apart(int[] array2, int i, int j , boolean flag) {
// TODO Auto-generated method stub
if(i >= j) return ;
int p;
p = (i+j)/2;
apart(array2 , i , p , flag);
apart(array2 , p+1 , j , flag);
merge(array2 , i , p , j , flag);
}
private static void merge(int[] array2, int i, int p, int j , boolean flag) {
// TODO Auto-generated method stub
int [] arr = new int [j-i+1];
int m , n ,index;
m = i ;
n = p+1;
index = 0;
while(m <= p&&n <= j){
if((array2[m]>=array2[n]&&flag)||(array2[m]<array2[n]&&!flag))
{
arr[index] = array2[n];
++index;
++n;
}
else
{
arr[index] = array2[m];
++index;
++m;
}
}
while(m <= p)
{
arr[index] = array2[m];
++index;
++m;
}
while(n <= j)
{
arr[index] = array2[n];
++index;
++n;
}
for(int x = i ; x <= j ; ++ x)
array2[x] = arr[x-i];
}
算法複雜度:每個 分治都會有一個合併,經過log(n)次後,分成最小數組,每次都會有n次合併操作,即
nlog(n)
算法比較: 歸併排序的效率是比較高的,設數列長爲N,將數列分開成小數列一共要logN步,每步都是一個合併有序數列的過程,時間複雜度可以記爲O(N),故一共爲O(N*logN)。因爲歸併排序每次都是在相鄰的數據中進行操作,所以歸併排序在O(N*logN)的幾種排序方法(快速排序,歸併排序,希爾排序,堆排序)也是效率比較高的