演算法導論學習之六:歸併排序
一、原理
歸併排序是建立在歸併操作上的一種有效的排序演算法,該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱為二路歸併。
歸併過程為:比較a[i]和a[j]的大小,若a[i]≤a[j],則將第一個有序表中的元素a[i]複製到r[k]中,並令i和k分別加上1;否則將第二個有序表中的元素a[j]複製到r[k]中,並令j和k分別加上1,如此迴圈下去,直到其中一個有序表取完,然後再將另一個有序表中剩餘的元素複製到r中從下標k到下標t的單元。
歸併排序的演算法我們通常用遞迴實現,先把待排序區間[s,t]以中點二分,接著把左邊子區間排序,再把右邊子區間排序,最後把左區間和右區間用一次歸併操作合併成有序的區間[s,t]。
package sort;
import java.util.Arrays;
/**
* Created by zhaomingwei on 16/4/9.
*/
public class MergeSortTest {
public static void main(String[] args) {
int[] a = {36, 24, 76, 11, 45, 64, 21, 69, 19, 36};
mergeSort(a,0,a.length -1);
System.out.println(Arrays.toString(a));
}
//分 + 合
public static void mergeSort(int[] a,int low,int high){
//退出遞迴條件
if (low >= high){
return;
}
int div = (low+high)/2;
mergeSort(a,low,div);
mergeSort(a,div+1,high);
merge(a,low,div,high);
}
//合併
public static void merge(int[] a,int low,int div,int high){
int len1 = div - low + 1;
int len2 = high - div;
int[] L = new int[len1];
int[] H = new int[len2];
copyArray(a,L,low,div);
copyArray(a,H,div+1,high);
int i = 0;
int j = 0;
for (int k = low; k <= high; k++){
if (i < len1&&j < len2 && L[i]>H[j]){
a[k] = H[j];
j++;
}else if(i < len1){
a[k] = L[i];
i++;
}else if(j < len2){
a[k] = H[j];
j++;
}
}
}
//複製陣列
public static void copyArray(int[] fromArr,int[] toArr,int start,int end){
for (int i=0;i<= end - start;i++){
toArr[i] = fromArr[start+i];
}
}
}
根據演算法書籍上的程式碼 基本程式碼
public class BaseMethod {
/**
* 判斷v是否小於w
*
* @param v
* @param w
* @return
*/
public static boolean less(Comparable v, Comparable w) {
return v.compareTo(w) < 0;
}
/**
* 交換索引為i,j位置元素
*
* @param a
* @param i
* @param j
*/
public static void exch(Comparable[] a, int i, int j) {
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}
/**
* 測試是否被排序,按升序排序
*
* @param a
* @return
*/
public static boolean isSorted(Comparable[] a) {
for (int i = 1; i < a.length; i++) {
if (less(a[i], a[i - 1])) {
return false;
}
}
return true;
}
}
排序程式碼:
import java.util.Arrays;
public class Merge extends BaseMethod {
private static Comparable[] aux;
/**
* 自頂向下的遞迴排序
* @param a
*/
public static void sort(Comparable[] a) {
aux = new Comparable[a.length];
sort(a, 0, a.length - 1);
}
private static void sort(Comparable[] a, int lo, int hi) {
if (lo >= hi) {
return;
}
int mid = lo + (hi - lo) / 2;
sort(a, lo, mid);
sort(a, mid+1, hi);
merge(a, lo, mid, hi);
}
/**
* 自底向上排序
* @param a
*/
public static void sortDownUp(Comparable[] a){
int n = a.length;
aux = new Comparable[n];
for (int sz = 1;sz<n;sz=sz+sz){
for (int lo = 0; lo < n-sz; lo+=sz+sz) {
merge(a,lo,lo+sz-1,Math.min(lo+sz+sz-1,n-1));
}
}
}
private static void merge(Comparable[] a, int lo, int mid, int hi) {
int i = lo;
int j = mid + 1;
for (int k = lo; k <= hi; k++) {
aux[k] = a[k];
}
for (int k = lo; k <= hi; k++) {
if (i > mid) {
/**左邊用盡 i>mid*/
a[k] = aux[j++];
} else if (j > hi) {
/**右邊用盡 j>hi*/
a[k] = aux[i++];
}else if (less(aux[j],a[i])){
a[k] = aux[j++];
}else{
a[k] = aux[i++];
}
}
}
public static void main(String[] args) {
Integer[] a = {2, 3, 1, 8, 0, 5, 4, 6, 9, 7};
sortDownUp(a);
System.out.println(Arrays.toString(a));
}
}
相關文章
- 從零開書學演算法(導論)之歸併排序演算法排序
- 演算法導論學習之三:排序之C語言實現:選擇排序,插入排序,歸併排序演算法排序C語言
- 演算法學習 – 歸併排序演算法排序
- 演算法學習 - 歸併排序演算法排序
- 演算法導論學習之五:快速排序演算法排序
- 排序演算法之 '歸併排序'排序演算法
- 演算法之歸併排序演算法排序
- 排序演算法總結之歸併排序排序演算法
- 排序演算法之「歸併排序(Merge Sort)」排序演算法
- 排序演算法__歸併排序排序演算法
- 排序演算法:歸併排序排序演算法
- 歸併排序--排序演算法排序演算法
- 排序演算法 - 歸併排序排序演算法
- 排序演算法——歸併排序排序演算法
- 排序演算法(歸併排序)排序演算法
- 演算法導論學習之二:插入排序演算法排序
- 演算法導論學習之一:氣泡排序演算法排序
- 演算法之常見排序演算法-氣泡排序、歸併排序、快速排序演算法排序
- 排序演算法之歸併,快速,堆和桶排序演算法
- 演算法導論_第六章_堆排序演算法排序
- 複習資料結構:排序演算法(四)——歸併排序資料結構排序演算法
- 演算法:排序連結串列:歸併排序演算法排序
- 演算法與資料結構高階排序演算法之歸併排序演算法資料結構排序
- [排序] 歸併排序排序
- 分治法演算法學習(一)——歸併排序、求最大子陣列和演算法排序陣列
- 演算法(氣泡排序,快排,歸併排序)演算法排序
- 演算法導論-堆排序演算法排序
- 演算法導論-快速排序演算法排序
- 歸併排序排序
- 從演算法開始[歸併排序]演算法排序
- 快速排序&&歸併排序排序
- 【分治演算法】歸併排序,快速排序和漢諾塔演算法排序
- 演算法系列(四)排序演算法中篇--歸併排序和快速排序演算法排序
- 資料結構與演算法——排序演算法-歸併排序資料結構演算法排序
- 《演算法導論》學習筆記演算法筆記
- 歸併排序演算法(merge_Sort)排序演算法
- 四、歸併排序 && 快速排序排序
- java歸併排序Java排序