1.题目
给定你一个长度为n的整数数列。
请你使用归并排序对这个数列按照从小到大进行排序。
并将排好序的数列按顺序输出。
输入格式
输入共两行,第一行包含整数 n。
第二行包含 n 个整数(所有整数均在1~109范围内),表示整个数列。
输出格式
输出共一行,包含 n 个整数,表示排好序的数列。
数据范围
1≤n≤100000
输入样例:
5
3 1 2 4 5
输出样例:
1 2 3 4 5
2.解题
分治思想
(1)确定分界点mid,即数组中间
(2)递归排序左边和右边
(3)归并:将两个有序的数组合并为一个数组
归并排序是一种稳定的排序方法,快排不稳定。
java:
import java.util.Scanner;
class Main{
public static int[] mergeSort(int[] arr, int low, int high){
if(low < high){
int mid = (low + high) / 2;
mergeSort(arr, low, mid);//递归排序左边
mergeSort(arr, mid + 1, high);//递归排序右边
merge(arr, low, mid, high);//合并
}
return arr;
}
//合并
public static void merge(int[] arr, int low, int mid, int high){
int[] tmp = new int[high - low + 1];
int i = low, j = mid + 1, k = 0;
//比较元素大小,按从小到大顺序讲元素放入tmp
while(i <= mid && j <= high){
if(arr[i] <= arr[j]){//注意:如果这里是严格小于的话,就不是稳定的排序
tmp[k++] = arr[i++];
}else{
tmp[k++] = arr[j++];
}
}
//将左边剩下的元素放入tmp
while(i <= mid){
tmp[k++] = arr[i++];
}
//将右边剩下的元素放入tmp
while(j <= high){
tmp[k++] = arr[j++];
}
for(int l = 0; l < high - low + 1; l++){
arr[l + low] = tmp[l];
}
}
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
int n = Integer.parseInt(scan.nextLine());
int[] arr = new int[n];
String[] s_arr = scan.nextLine().split(" ");
for (int i = 0; i < n; i++){
arr[i] = Integer.parseInt(s_arr[i]);
}
int[] res = mergeSort(arr, 0, n - 1);
for (int j = 0; j < n; j++){
System.out.print(res[j] + " ");
}
scan.close();
}
}
c++:
#include <iostream>
using namespace std;
void mbrlen(int arr[], int low, int mid, int high)
{
int tmp[high - low + 1];
int i = low, j = mid + 1, k = 0;
while (i <= mid && j <= high)
if (arr[i] < arr[j])
tmp[k++] = arr[i++];
else
tmp[k++] = arr[j++];
while (i <= mid)
tmp[k++] = arr[i++];
while (j <= high)
tmp[k++] = arr[j++];
for (int p = 0; p < high - low + 1; p++)
arr[p + low] = tmp[p];
}
void merge_sort(int arr[], int low, int high)
{
if (low >= high)
return;
int mid = (low + high) / 2;
merge_sort(arr, low, mid);
merge_sort(arr, mid + 1, high);
mbrlen(arr, low, mid, high);
}
int main()
{
int n = 11;
int arr[] = {3, 2, 5, 4, 1, 7, 3, 23, 54, 76, 87};
merge_sort(arr, 0, n - 1);
for (int i = 0; i < n; i++)
{
cout << arr[i] << endl;
}
}
注意:合并函数中排序时的i和j控制
精选题解
c++:
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], tmp[N];
void merge_sort(int q[], int l, int r)
{
if (l >= r)
return;
int mid = l + r >> 1;
merge_sort(q, l, mid), merge_sort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r)
if (q[i] <= q[j])
tmp[k++] = q[i++];
else
tmp[k++] = q[j++];
while (i <= mid)
tmp[k++] = q[i++];
while (j <= r)
tmp[k++] = q[j++];
for (i = l, j = 0; i <= r; i++, j++)
q[i] = tmp[j];
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
merge_sort(a, 0, n - 1);
for (int i = 0; i < n; i++)
printf("%d ", a[i]);
return 0;
}
时间复杂度
$n*logn=nlogn$
时间复杂度为O(nlogn)