归并排序:小和问题
Posted causewang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了归并排序:小和问题相关的知识,希望对你有一定的参考价值。
归并排序:小和问题
在一个数组中,每一个元素左边比当前元素值小的元素值累加起来,叫做这个数组的小和
例如:[2, 3, 4, 1, 5]
2 左边比 2 小的元素:无
3 左边比 3 小的元素:2
4 左边比 4 小的元素:2,3
1 左边比 1 小的元素:无
5 左边比 5 小的元素:2, 3, 4, 1
小和small_sum = 2 + 2 + 3 + 2 + 3 + 4 + 1 = 17
解法
利用归并排序的性质,将数组二分,递归排序,在放入辅助数组的时候,由于左右两个数组都是排好序的,所以当右边有1个数大于左边某元素时,右边右面的数肯定大于该元素,只需将该元素乘以大于其元素个数,累加到sum上即可
如数组[2, 3, 4, 0, 5, 6, 1, 8]
递归调用归并排序,形成如下:
? [2, 3, 4, 0] [5, 6, 1, 8]
[2, 3] [4, 0] [5, 6] [1, 8]
[2] [3] [4] [0] [5] [6] [1] [8]
由于递归的特性,先对2和3进行排序,放入辅助数组时, 左边2小于右边3,由于右边3后面没有其他数了,所以sum+=2x1,2和3从小到大排序。然后计算4和0,4大于0,不累加,直接进行排序。而后计算[2, 3]和[0, 4],放入辅助数组时,左边第一位2大于右边第一位0,由于左边是从小到大排序的,2都比0大了,2后面的数字不可能比0小,所以直接将0放入辅助数组,指针指向4, 2比4小,但是4后面没有更多数字了,所以2累加到sum上,sum+=2x1,然后2放入辅助数组,左边指向3, 3小于4,累加上sum+=3x1,然后完成排序,产生[0, 2, 3, 4]。右边同理,最后[0, 2, 3, 4]和[1,5,6,8]进行排序, 左边0和右边1进行比较,0比1小,由于右边是从大到小排好序的,所以后面的数字都比0大,直接累加sum+=0*4;其他的元素同理;
代码
#include <stdio.h>
int helperArr[10];
int Merge(int arr[], int l, int mid, int r)
{
int i = l;
int p1 = l;
int p2 = mid + 1;
int sum = 0;
while (p1 <= mid && p2 <= r) {
sum += arr[p1] < arr[p2] ? arr[p1] * (r - p2 + 1) : 0;
helperArr[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while (p1 <= mid) {
helperArr[i++] = arr[p1++];
}
while (p2 <= r) {
helperArr[i++] = arr[p2++];
}
for (; l <= r; l++) {
arr[l] = helperArr[l];
}
return sum;
}
int MergeSort(int arr[], int l, int r)
{
if (l == r) {
return 0;
}
int mid = l + ((r - l) >> 1); // =(l+r)/2 因为l+r有可能会溢出,所以改成减法的方式
return MergeSort(arr, l, mid) + MergeSort(arr, mid + 1, r) + Merge(arr, l, mid, r);
}
int SmallSum(int arr[], int size)
{
if (arr == NULL || size < 2) {
return 0;
}
return MergeSort(arr, 0, size - 1);
}
void PrintArr(int arr[], int size)
{
for (int i = 0; i < size; ++i) {
printf("%d ", arr[i]);
}
printf("
");
}
int main()
{
int arr[10] = {6, 0, 5, 3, 15, 21, 13, 9, 12, 8};
PrintArr(arr, 10);
int ret = SmallSum(arr, 10);
PrintArr(arr, 10);
printf("小和是:%d", ret);
return 0;
}
以上是关于归并排序:小和问题的主要内容,如果未能解决你的问题,请参考以下文章