歸併排序:採用分治法排序,先分後治; 將數組分成兩個數列,再將左子數列分成兩個數列,再將右子數列分成兩個數列...直到每一個子數列只有一個數字; 然後就是治,也稱爲merge;將兩個有序數列合併成一個有序數列的過程;
代碼實現與理解-----遞歸實現:
int a[] = {2, 3, 5, 6, 9, 0, 4, 7, 8};
// 歸併排序
sort(a, 0, a.length-1);
for (int h=0;h < a.length;h ++){
Log.i("chy1234","==結果數據==="+a[h]);
}
/******************************************************/
/**
* 遞歸進行歸併排序
*
* @param a
* @param left
* @param right
*/
private void sort(int []a, int left, int right){
if (left == right){
return;
}
// 找到數列中間點
int mid = left + (right - left)/2;
// 對於中間點左邊進行排序
sort(a, left, mid);
// 對於中間點右邊進行排序
sort(a, mid +1, right);
// 排序完成後,合併左右兩個數列
merge(a,left, mid+1, right);
}
/**
* 將兩個有序的數列合併成爲一個有序的數列
* @param a 數列
* @param leftPoint 左起始點
* @param rightPoint 右起始點
* @param rightBound 右邊緣
*/
private void merge(int []a, int leftPoint, int rightPoint, int rightBound){
// 找到中間位置
int mid = rightPoint -1;
// 初始化數組用來裝臨時數據(長度爲要排序的數列長度)
int result[] = new int[rightBound - leftPoint +1];
int i = leftPoint;
int j = rightPoint;
int k = 0;
// 遍歷兩邊的數列,按照順序填入result[]中
while(i <= mid && j <= rightBound) {
if (a[i] <= a[j]) {
result[k ++] = a[i ++];
} else {
result[k ++] = a[j ++];
}
}
// 如果左邊數列有剩餘,填入result[]尾部
while (i <= mid) {
result[k++] = a[i++];
}
// 如果右邊數列有剩餘,填入result[]尾部
while (j <= rightBound) {
result[k++] = a[j++];
}
// 將排序好的數列result[]重新賦值給初始數列a[]
for (int h = 0 ; h < result.length; h ++){
a[leftPoint ++] = result[h];
}
}
代碼的理解與實現--非遞歸實現:
int a[] = {5, 3, 4, 8, 9, 0, 2, 6, 7};
/**
* 外層循環定義合併次數
* 根據合併數組內的元素個數(1,2,4,8.....)得出外合併次數
* 第1次合併 1 個元素 第2次合併2個元素;
* 第3次合併 4 個元素 ...
*/
for (int i = 1; i < a.length; i = i * 2) {
int left = 0;
int mid = left + i - 1;
int right = mid + i;
while (right < a.length) {
merge(a, left, mid+1, right);
left = right + 1;
mid = left + i - 1;
right = mid + i;
}
if (left < a.length && mid < a.length) {
merge(a, left, mid+1, a.length - 1);
}
}
for (int h = 0; h < a.length; h++) {
Log.i("chy1234", "==結果數據===" + a[h]);
}
/*************merge 方法與遞歸的 merge 保持一致******************/
/**
* 將兩個有序的數列合併成爲一個有序的數列
*
* @param a 數列
* @param leftPoint 左起始點
* @param rightPoint 右起始點
* @param rightBound 右邊緣
*/
private void merge(int[] a, int leftPoint, int rightPoint, int rightBound) {
// 找到中間位置
int mid = rightPoint - 1;
// 初始化數組用來裝臨時數據(長度爲要排序的數列長度)
int result[] = new int[rightBound - leftPoint + 1];
int i = leftPoint;
int j = rightPoint;
int k = 0;
// 遍歷兩邊的數列,按照順序填入result[]中
while (i <= mid && j <= rightBound) {
if (a[i] <= a[j]) {
result[k++] = a[i++];
} else {
result[k++] = a[j++];
}
}
// 如果左邊數列有剩餘,填入result[]尾部
while (i <= mid) {
result[k++] = a[i++];
}
// 如果右邊數列有剩餘,填入result[]尾部
while (j <= rightBound) {
result[k++] = a[j++];
}
// 將排序好的數列result[]重新賦值給初始數列a[]
for (int h = 0; h < result.length; h++) {
a[leftPoint++] = result[h];
}
}
歸併排序的記憶: 遞歸實現,難點在於merge方法