归并排序的代码:时间复杂度O(N*logN);
1.递归写法
#include<bits/stdc++.h>
using namespace std;
int help[6];
void merge(int *arr, int l, int m, int r) {
int a = l;
int b = m + 1;
int i = l;
while (a <= m && b <= r) {
help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++];
}
while (a <= m)
help[i++] = arr[a++];
while (b <= r)
help[i++] = arr[b++];
while (l <= r){
arr[l]=help[l];
l++;
}
}
void mergesort(int* arr, int l, int r) {
if (l == r) return ;
int mid = l + ((r - l) >> 1);
mergesort(arr, l, mid);
mergesort(arr, mid + 1, r);
merge(arr, l, mid, r);
}
int main() {
int arr[5] = {1, 2, 3, 4, 5};
mergesort(arr, 0, 4);
for (int i = 0; i < 5; i++)
cout << arr[i] << " ";
return 0;
}
2.非递归写法
#include<bits/stdc++.h>
using namespace std;
int help[6];
void merge(int *arr, int l, int m, int r) {
int a = l;
int b = m + 1;
int i = l;
while (a <= m && b <= r) {
help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++];
}
while (a <= m)
help[i++] = arr[a++];
while (b <= r)
help[i++] = arr[b++];
for(int i=l;i<=r;i++)
arr[i]=help[i];
}
int main() {
int arr[5] = {1, 2, 3, 4, 5};
int step = 1;
int l = 0, r = 0, m = 0;
for (l, r, step; step < 5; step <<= 1) {
l = 0;
while (l < 5) {
m = l + step - 1;
if (m + 1 >= 5) break;
r = min(5 - 1, l + 2 * step - 1);
merge(arr, l, m, r);
l = r + 1;
}
}
for (int i = 0; i < 5; i++)
cout << arr[i] << " ";
return 0;
}
具体练习可在数组排序
归并排序和分治的综合应用:
视频连接归并分治
我们用小数和 来举例说明:
描述
数组小和的定义如下:
∑i=1nfi (其中 fi 的定义是第 i 个数的左侧小于等于 si 的个数)。例如,数组 s = [1, 3, 5, 2, 4, 6] ,在 s[0] 的左边小于或等于 s[0] 的数的和为 0 ; 在 s[1] 的左边小于或等于 s[1] 的数的和为 1 ;在 s[2] 的左边小于或等于 s[2] 的数的和为 1+3=4 ;在 s[3] 的左边小于或等于 s[3] 的数的和为 1 ;
在 s[4] 的左边小于或等于 s[4] 的数的和为 1+3+2=6 ;在 s[5] 的左边小于或等于 s[5] 的数的和为 1+3+5+2+4=15 。所以 s 的小和为 0+1+4+1+6+15=27
给定一个数组 s ,实现函数返回 s 的小和
输入描述:
第一行有一个整数N。表示数组长度
接下来一行N个整数表示数组内的数
输出描述:
一个整数表示答案
要求一个数组的小数的和,可以将数组划分为左右两部分,分别求左数组的小数和和右数组的小数
和,显然这并不是答案,因为左边数组的元素可能是右边数组元素的小数,所以还得加上左边数组
跨越右数组的小数和。当我们在求跨左右数组的小数和时,如果左右数组的元素分别有序,当我们
求右边数组第一个元素在左边数组的小数和时,可以安排一个指针遍历左数组来求;那么第二个元
素在左数组的小数和可以在第一个元素的基础上继续遍历左数组累加,所以只需遍历一遍左右数组
就可以求出跨左右数组的小数和,更便于我们计算,那么,这就符合归并分治的思想。
#include <iostream>
using namespace std;
int help[6];
int merge(int l, int mid, int r,int* nums) {
int sum = 0, ans = 0;
int a = l;
for (int i = mid + 1; i <= r; i++) {
while (nums[i] >= nums[a]&&a<=mid) {//找跨左右小数的和
sum += nums[a];
a++;
}
ans += sum;
}
int i = l,j=mid+1;
int pos = l;
while (i <= mid && j <= r) {//归并过程
if (nums[i] >= nums[j])
help[pos++] = nums[j++];
else help[pos++] = nums[i++];
}
while (i <= mid)
help[pos++] = nums[i++];
while (j <= r)
help[pos++] = nums[j++];
for(int i=l;i<=r;i++){
nums[i]=help[i];
}
return ans;
}
int min_num(int l, int r,int* nums) {
if (l == r) return 0;
int mid = l + ((r - l) >> 1);
return min_num(l, mid,nums) + min_num(mid + 1, r,nums ) + merge(l,mid,r,nums);
}
int main() {
int nums[5] = {1,2,3,4,5};
int result= min_num(0, 4,nums);
cout << result;
return 0;
}
类似的题目:翻转对