歸併演算法詳解
MergeSort,歸併排序。
[1] 歸併排序的原理
1.1 將兩個有序陣列合併成一個有序陣列
兩個陣列,每一個陣列內部都是有序的,比如:
a{5,7} 和 b{6,11,37}
我們申請足夠大的空間,來放排好序的陣列。比如這個陣列叫 c{}。
每次取兩個陣列中最小的數,進行比較,小的取出放入 c{}。
如此將兩個陣列中的元素都取完,全部放入 c{},c{} 中就是一個有序的陣列。比如:
第1次:5和6比較,5較小,所以 a{7}, b{6,11,37} -> c{5}
第2次:7和6比較,6較小,所以 a{7}, b{11,37} -> c{5,6}
第3次:7和11比較,7較小,所以 a{}, b{11,37} -> c{5,6,7}
第4次:a{} 空了,所以 b{} 中剩下的都是排好序的大的,所以 a{}, b{} -> c{5,6,7,11,37}
1.2 遞迴產生有序陣列
每次:把一個無序陣列,分成前後兩半(根據陣列中的元素個數,就可以確定到哪裡是一半),首先對前一半進行遞迴呼叫,然後對後一半進行遞迴呼叫。最後歸併,產生一個完整的有序陣列。
比如:{7, 5, 37, 6, 11},
一共有5個元素,5/2=2,所以分成 {7,5} {37,6,11}。
對{7,5} 進行遞迴呼叫,一共有2個元素,2/2=1,所以分成 {7} {5}。
對{7} 進行遞迴呼叫,發現到頭了,返回。
對{5} 進行遞迴呼叫,發現到頭了,返回。
於是歸併 {7} {5},得到有序陣列 {5,7},返回。
對{37,6,11} 進行遞迴呼叫,一共有3個元素 3/2=1,所以分成 {37} {6,11}。
對{37} 進行遞迴呼叫,發現到頭了,返回。
對{6,11} 進行遞迴呼叫,一共有2個元素 2/2=1,所以分成 {6} {11}。
對{6} 進行遞迴呼叫,發現到頭了,返回。
對{11} 進行遞迴呼叫,發現到頭勒,返回。
於是歸併 {6} {11},得到有序陣列 {6,11},返回。
於是歸併 {37} {6,11},得到有序陣列 {6,11,37},返回。
於是歸併 {5,7} {6,11,37},得到有序陣列 {5,6,7,11,37},返回。排序完成。
[2] 歸併排序的實現
package testAlgorithm;
import java.util.Arrays;
/**
* @author derek zhan
* @version
*/
@SuppressWarnings("unchecked")
public class MergeSortTest
{
//排序中的臨時陣列
private Comparable [] tmpArray ;
public static void main(String[] args)
{
Integer [] obj = {1,4,7,2,5,8};
MergeSortTest mst = new MergeSortTest();
mst.sort(obj);
System.out.println(Arrays.toString(obj));
Integer[] obj2 = {8,5,2,7,4,1};
mst.mergeSort2(obj2);
System.out.println(Arrays.toString(obj2));
}
/**
* *利用歸併排序演算法對陣列obj進行排序
*/
public void sort(Comparable[] obj) {
tmpArray = new Comparable[obj.length];// 初始化中間陣列
mergeSort1(obj, 0, obj.length - 1); // 歸併排序
tmpArray = null;
}
//第一個種方法
/**
* 遞迴劃分成2個陣列
* @param obj 要排序的陣列
* @param left 陣列中第一個元素下標
* @param right 陣列最後一個元素的下標
*/
public void mergeSort1(Comparable[] obj,int left,int right){
if(left < right){//只要不是陣列的最後一個元素
int center = (left+right)/2;
mergeSort1(obj, left, center); //劃分成左陣列
mergeSort1(obj, center+1, right);//劃分成右陣列
merge1(obj, left, center, right);//合併2一個陣列並排序
}
}
//第二種方法
public void mergeSort2(Comparable[] obj){
int n = obj.length;
if(n<=1) return; //如果只有一個元素則返回.
Comparable left[] = new Comparable[n/2]; //左陣列
Comparable right[] = new Comparable[n-n/2]; //右陣列
for(int i=0,leftPos=left.length; leftPos<obj.length; i++,leftPos++){
if(i<left.length){ //給左陣列賦值
left[i] = obj[i];
}
//給右陣列賦值
right[i] = obj[leftPos];
}
mergeSort2(left);
mergeSort2(right);
merge2(obj, left, right);
}
/**
* 合併陣列並排序
* @param obj 要合併的陣列
* @param left 左邊陣列第一個元素下標
* @param center 左邊陣列最後一個元素下標
* @param right 右邊陣列最後一個元素下標
*/
public void merge1(Comparable[] obj,int left,int center,int right){
int midd = center+1;
int temp = left;
int third = left;
while(left <= center && midd <= right){
if(obj[left].compareTo(obj[midd])<=0){ //比較2個陣列中的值,把小值放入臨時陣列
tmpArray[third++] = obj[left++];
}else{
tmpArray[third++] = obj[midd++];
}
}
//如果第一個陣列已經全部比較完了,那麼我們只要直接複製第二個陣列的條目到合併陣列中即可
while(midd<=right){
tmpArray[third++] = obj[midd++];
}
//如果第二個陣列已經全部比較完了,那麼我們只要直接複製第一個陣列的條目到合併陣列中即可
while(left <= center){
tmpArray[third++] = obj[left++];
}
//拷貝bridge to obj陣列
while(temp<=right){
obj[temp] = tmpArray[temp];
temp++;
}
}
//第二種合併方法
public void merge2(Comparable[] obj,Comparable[] left,Comparable[] right){
int leftLength = left.length-1;
int rightLength = right.length-1;
int k=0;
int leftPos=0,rightPos=0; // left陣列下標, right陣列下標
while(leftPos<=leftLength||rightPos<=rightLength){
Comparable temp = null;
if(leftPos>leftLength){ //如果第一個陣列已經全部比較完了,那麼我們只要直接複製第二個陣列的條目到合併陣列中即可
temp=right[rightPos++];
}else if(rightPos>rightLength){ //如果第二個陣列已經全部比較完了,那麼我們只要直接複製第一個陣列的條目到合併陣列中即可
temp=left[leftPos++];
}else if(left[leftPos].compareTo(right[rightPos])>0){ //把比較的兩個條目中關鍵值小的放到合併陣列中
temp=right[rightPos++];
}else{
temp=left[leftPos++];
}
obj[k++]=temp; //把比較完的值放入陣列
}
}
}
最後執行結果:
[1, 2, 4, 5, 7, 8]
[1, 2, 4, 5, 7, 8]
相關文章
- 歸併排序詳解及應用排序
- js 歸併演算法JS演算法
- 演算法之歸併排序演算法排序
- 排序演算法__歸併排序排序演算法
- 排序演算法:歸併排序排序演算法
- 歸併排序--排序演算法排序演算法
- 排序演算法 - 歸併排序排序演算法
- 排序演算法——歸併排序排序演算法
- 排序演算法(歸併排序)排序演算法
- 排序演算法之 '歸併排序'排序演算法
- 演算法學習 – 歸併排序演算法排序
- 演算法學習 - 歸併排序演算法排序
- 全面瞭解歸併排序演算法及程式碼實現排序演算法
- 從演算法開始[歸併排序]演算法排序
- 歸併排序演算法(merge_Sort)排序演算法
- 演算法:排序連結串列:歸併排序演算法排序
- 排序演算法總結之歸併排序排序演算法
- 演算法學習---歸併演算法簡單記錄演算法
- 排序演算法之歸併,快速,堆和桶排序演算法
- 【資料結構與演算法】歸併排序資料結構演算法排序
- 排序演算法之「歸併排序(Merge Sort)」排序演算法
- 演算法(氣泡排序,快排,歸併排序)演算法排序
- 資料結構與演算法——歸併排序資料結構演算法排序
- 詳解迴歸測試
- 資料結構與演算法——排序演算法-歸併排序資料結構演算法排序
- 歸併排序排序
- 手寫演算法並記住它:歸併排序演算法排序
- 【分治演算法】歸併排序,快速排序和漢諾塔演算法排序
- 演算法導論學習之六:歸併排序演算法排序
- 常見的排序演算法:冒泡、快排、歸併排序演算法
- 史上最清晰的「歸併排序」講解排序
- 【演算法】排序02——歸併排序介紹及其在分治演算法思想上與快排的區別(含歸併程式碼)演算法排序
- 單連結串列的冒泡,快排,選擇,插入,歸併等多圖詳解
- 演算法系列(四)排序演算法中篇--歸併排序和快速排序演算法排序
- java歸併排序Java排序
- [java]歸併排序Java排序
- [排序] 歸併排序排序
- 歸併排序模板排序