归并排序
归并排序
归并排序的核心思想是分而治之(Devide And Conquer)。将大问题拆分成子问题,分别对子问题进行求解之后,并将所有的子问题的解合并之后即可。有以下三个解题步骤。分解,解决,合并。
-
分解。单独一个数肯定是有序的,因此要分解的子问题目的就是分解成一个只含有一个数的数组。第一次分解为2个数组,第二次分解为4,依次类推。直到分解为n个子数组为止。
-
解决+合并。对于两个有序的数组进行合并。创建一个额外数组,然后每次比较分别两个数组的中的最小值后将最小值删除并且有序放入额外数组中。将左右两个数组都取空之后,额外数组的排序也就完成了。
从以上情况可以判断,无论数组大小是否奇数还是偶数,分解后都存在n个数组。开始合并到最后,单词次都是两个数组参与。
归并排序demo
《算法》一书的Java教学版本,易于理解
package Sort;
import java.util.Arrays;
/**
* 合并排序
*
* @author Ldity
* @date 2020/8/10 21点48分
*/
public class MergeSort {
private static final int[] nums = {2,51,3,21,4,512,54};
public static void merge(int[] arr, int left, int mid, int right){
int n = arr.length;
int length = right - left + 1;
int[] tmp = new int[length];
int i = left;
int j = mid + 1;
int k = 0;
while(i <= mid && j <= right){
if(arr[i] < arr[j]){
tmp[k++] = arr[i++];
}
else {
tmp[k++] = arr[j++];
}
}
while(i <= mid) tmp[k++] = arr[i++];
while(j <= right ) tmp[k++] = arr[j++];
System.arraycopy(tmp, 0, arr, left, length);
}
public static void mergeSort(int[] arr, int left, int right){
if (left < right){
int mid = (right + left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
public static void main(String[] args){
int left = 0;
int right = nums.length - 1;
mergeSort(nums, left, right);
System.out.println(Arrays.toString(nums));
}
}
Acwing巨佬C++版本。优雅高效
#include <iostream>
using namespace std;
const int N = 1e6+10;
int q[N];
void merge_sort(int q[], int l, int r){
if (l >= r) return;
int i = l;
int mid = l + r >> 1;
int j = mid + 1;
merge_sort(q, i, mid);
merge_sort(q, j, r);
int k = 0;
int temp[r - l + 1];
// 两个有序数组,然后进行比对
while (i <= mid && j <= r){
if (q[i] < q[j]){
temp[k++] = q[i++];
} else{
temp[k++] = q[j++];
}
}
//处理剩下的数据部分
while (i <= mid) temp[k++] = q[i++];
while (j <= r) temp[k++] = q[j++];
for (int i = l, j = 0; i <= r; ++i, ++j) {
q[i] = temp[j];
}
return;
}
int main(){
int n;
scanf("%d ", &n);
for (int i = 0; i < n; ++i) {
scanf("%d", &q[i]);
}
merge_sort(q, 0, n - 1);
for (int j = 0; j < n; ++j) {
printf("%d ", q[j]);
}
}