归并排序及求小和问题

归并排序
归并排序是先将序列的每相邻的两个数字进行归并操作,形成两两一对排序好的元素,接着将上述序列再次归并,形成包含四个元素的序列。重复上述步骤,直到所有元素排序完毕。
归并排序的C++版本完整程序及测试代码如下:

#include <iostream>
using namespace std;
void mergeSort(int arr[], int length);
void merge(int arr[], int l, int m, int r);
void sortProcess(int arr[], int L, int R)
{
	if(L == R) {
		return;
	}
	int mid = (L + R)/2;
	sortProcess(arr, L, mid);
	sortProcess(arr, mid+1, R);
	merge(arr, L, mid, R);
}
void mergeSort(int arr[], int length)
{
	if (length < 2) {
		return ;
	}
	sortProcess(arr, 0, length - 1);
}
void merge(int arr[], int l, int m, int r)
{
	int help[r - l + 1] = {0};
	int i = 0;
	int p1 = l;
	int p2 = m + 1;
	while(p1 <= m && p2 <= r) {
		help[i++] = arr[p1] < arr[p2] ? arr[p1++]:arr[p2++];
	} 
	while(p1 <= m) {
		help[i++] = arr[p1++];
	}
	while(p2 <= r) {
		help[i++] = arr[p2++];
	}
	for(i = 0; i < sizeof(help)/sizeof(help[0]); i++){
		arr[l + i] = help[i];
	}
	
} 
int main()
{
	int arr[] = {8, 4 , 1, 4, 5, 2, 3, 0};
	int len = sizeof(arr)/sizeof(arr[0]);
	mergeSort(arr, len);
	for(int i =0; i< len; i++) {
		cout<<arr[i]<<endl;
	}
}

arr数组的长度是8,先进入mergeSort函数,这个函数用于当前数组只有一个元素时直接返回,接着调用sortProcess(arr,0,7)函数,这个函数是要进行递归的。
递归的终止条件是L和R相等,所以该函数会一直向下递归,进入第二层sortProcess(arr,0,3);再进入第三层sortProcess(arr,0,1);接着进入第四层sortProcess(arr,0,0),同一层还有sortProcess(arr,1,1),这两个函数再往下执行都是直接返回,退回到第四层中执行merge(arr,0,0,1);从而将arr[0]和arr[1]这两个元素的顺序排好。在退回到三层执行sortProcess(arr,0,1)的下一句sortProcess(arr,2,3),将arr[2]和arr[3]这两个元素的顺序排好,执行merge(arr,2,2,3)。下一步再将arr[0],arr[1],arr[2],arr[3]这四个元素有序,左边的sortProcess(arr,4,7)与此类似。最终merge(arr,0,3,7)使整个数组全部有序。
求小和问题
求小和的意思是将数组中每一个数左边比它小的数累积起来,称为小和。求小和问题与归并排序的过程是类似的,下面举一个有六个元素的数组是如何求小和的的。
这六个元素分别是4,1,3,5,0,6。
依次往下分解,得到[1,4],[3]和[0],[5,6]。
参考递归排序的过程,[1,4]进行第一次merge,这时候mid=0,产生一个小和,接着[1,4]和[3]进行第二次merge,这时候mid=1,也是从mid之后比较后面的数与mid前面之间的数的大小,产生一个小和,依次类推。所以求小和问题可以直接在递归排序的程序中merge函数里面加上一行代码。

res += arr[p1] < arr[p2] ? (r - p2 +1) * arr[p1] : 0;

完整程序如下:

#include <iostream>
using namespace std;
int mergeSort(int arr[], int length);
int merge(int arr[], int l, int m, int r);
int sortProcess(int arr[], int L, int R)
{
	if(L == R) {
		return 0;
	}
	int mid = (L + R)/2;
 	return 	sortProcess(arr, L, mid)+sortProcess(arr, mid+1, R)+merge(arr, L, mid, R);
}
int  mergeSort(int arr[], int length)
{
	if (length < 2) {
		return 0 ;
	}
	sortProcess(arr, 0, length - 1);
}
int  merge(int arr[], int l, int m, int r)
{
	int res = 0;
	int help[r - l + 1] = {0};
	int i = 0;
	int p1 = l;
	int p2 = m + 1;
	while(p1 <= m && p2 <= r) {
		res += arr[p1] < arr[p2] ? arr[p1]*(r-m): 0;
		help[i++] = arr[p1] < arr[p2] ? arr[p1++]:arr[p2++];
	} 
	while(p1 <= m) {
		help[i++] = arr[p1++];
	}
	while(p2 <= r) {
		help[i++] = arr[p2++];
	}
	for(i = 0; i < sizeof(help)/sizeof(help[0]); i++){
		arr[l + i] = help[i];
	}
	return res;
	
} 
int main()
{
	
	int arr[] = {4, 8,16};
	int len = sizeof(arr)/sizeof(arr[0]);
	int res;
	res = mergeSort(arr, len);
	for(int i =0; i< len; i++) {
		cout<<arr[i]<<endl;
	}
	printf("The small sum is %d",res);	
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值