【归并排序,小和问题,利用C++实现】

发布于:2022-12-10 ⋅ 阅读:(251) ⋅ 点赞:(0)

1 归并排序(升序或降序只需在左右侧比较时修改即可)

  求数组左侧有序和右侧有序,然后合并左侧和右侧完成排序。

  对于数组a={1,4,2,5,3},mid=0+(4-0)/2=2,

第一步:从a的下标i=2处将a分为:左侧{1,4,2}右侧{5,3};

第二步:计算左侧的mid,将左侧{1,4,2}分为:左侧{1,4}右侧{2};

第三步:计算左侧的mid,将左侧{1,4}分为:左侧{1}右侧{4};

第四步:当不能进行分割时开始比较当前的左侧和右侧值进行排序,倒着执行到第一步完成数组a左侧的排序{1,2,4};

第五步:对数组a的右侧进行上述步骤,完成右侧排序{3,5};

最后:合并左侧{1,2,4}右侧{3,5},合并时若左侧a[i]<右侧a[j],先拷贝a[i],此为升序,若为降序则相反。 7-99999999999999

如图:

 

2 完整代码如下:

#include<iostream>
using namespace std;

//1.归并排序,利用递归,先将两侧排好序,再进行合并
//比较相邻序列
void merge(int arr[], int temp[], int start,int mid, int end)
{
	cout << "(start,mid,end)=" << "(" << start << "," << mid << "," << end << ")" << endl;
	int i = start, j = mid + 1, k = start;
	//将较小值放入temp
	while (i != mid+1 && j != end+1)
	{
		if (arr[i] <arr[j])
		{
			temp[k++] = arr[i++];
		}
		else
		{
			temp[k++] = arr[j++];
		}
	}
	//将多的数放到temp末尾
	while (i!= mid + 1)
	{
		temp[k++] = arr[i++];
	}
		
	while (j != end + 1)
	{
		temp[k++] = arr[j++];
	}
	
	//更新序列
	for (int i = start; i <= end; i++)
	{
		arr[i] = temp[i];
		cout << arr[i] << " ";
	}
	cout << endl;
}

//排序
void merge_sort(int arr[], int temp[], int start, int end)
{
	int mid = 0;
	if (start < end)
	{
		mid = start + (end - start) / 2;
		//递归调用
		merge_sort(arr, temp, start, mid);
		merge_sort(arr, temp, mid + 1, end);
		merge(arr, temp, start, mid, end);
	}
}

int main()
{
	int a[5] = {1,4,2,5,3};
	int t[5];
	merge_sort(a, t, 0, 4);
	for (int i = 0; i < 5; i++)
	{
		cout << a[i] << " ";
	}
	cout << endl;

	system("pause");
	system("cls");
	return 0;
}

3 小和问题 

 问题描述:在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和

以上述中a={1,4,2,5,3}为例:记小和为:res=0

(1)1左边比1小的数为0(1左边没有数字),res=0+0;

(2)4左边比4小的数为1,                                 res=0+1

(3)2左边比2小的数为1,                                  res=0+1+1

(4)5左边比5小的数为1,4,2,                            res=0+1+1+1+4+2

(5)3左边比3小的数为1,2,                               res=0+1+1+1+4+2+1+2=12

从上述可以得出比1的右侧比1大的个数为4,比4大的个数为1,比2大的数的个数为2,比5大的数的个数为0,比3大的数的个数为0

  小和  res=1*4 + 4*1 + 2*2 + 5*0 + 3*0=12

因此小和问题只需在归并排序过程中记录比当前数a[i]大的数的个数 num    res+=a[i]*num

注意:当左侧数等于右侧数,即:a[i]==a[j] 时应先拷贝右侧数,即 :temp=a[j],否则统计不出比当前数字大的数的个数.

4 小和详细代码:

#include<iostream>
using namespace	std;

/*
小和问题描述:
在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和
*/
//分段排序
int merge(int arr[], int temp[], int start, int mid, int end)
{
	cout << "(start,mid,end)=" << "(" << start << "," << mid << "," << end << ")" << endl;
	int i = start, j = mid+1, k = start;
	int res = 0;
	while(i != mid + 1 && j != end + 1)
	{
		//若左侧等于右侧先拷贝右侧,否则算不出比当前数大的数的个数
		if (arr[i] == arr[j])
		{
			temp[k++] = arr[j++];
		}
		else if (arr[i] < arr[j]) //注意此处不要写为arr[i++]<arr[j++]
		{
			res += (end - j + 1) * arr[i]; //num=end-j+1为比当前数a[i]大的数的个数
			temp[k++] = arr[i++];
		}
		else
		{
			temp[k++] = arr[j++];
		}
	}
	//将多余的数放到temp末尾
	while (i != mid + 1)
	{
		temp[k++] = arr[i++];
	}
	while (j != end + 1)
	{
		temp[k++] = arr[j++];
	}
	//更新a[]
	for (int i=start;i<= end;i++)
	{
		arr[i] = temp[i];
		cout << arr[i] << " ";
	}
	cout << endl;
	return res;
}

//递归排序
int merge_sort(int arr[], int temp[], int start, int end)
{
	int mid = 0;
	if (start == end) //此时不记录小和
	{
		return 0;
	}
	mid = start + (end - start) / 2;
	//递归调用
	return merge_sort(arr,temp,start,mid)
	+merge_sort(arr, temp, mid + 1, end)
	+merge(arr, temp, start, mid, end);
}

int main()
{
	//准备数组{ 2, 3, 4, 1, 2, 3, 8, 9, 0 };小和=5*2+3*3+2*4+4*1+3*2+2*3+1*8=
	int a[5] = { 1,4,2,5,3 };
	int t[5];
	int Sum = 1 * 4 + 4 * 1 + 2 * 2 + 5 * 0 + 3 * 0;

	int sum=merge_sort(a, t, 0, 4);
	cout << "a=";
	for (int i = 0; i < 5; i++)
	{
		cout << a[i] << ",";
	}
	cout << endl;
	cout << "验证Sum=" << Sum << endl;
	cout << "小和sum=" << sum << endl;
	return 0;
}

结果: 

这是作者的学习笔记,在此分享,仅供参考。因为作者水平有限,如有疏漏之处,还望批评指正。 


网站公告

今日签到

点亮在社区的每一天
去签到