赞
踩
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;
- }
结果:
这是作者的学习笔记,在此分享,仅供参考。因为作者水平有限,如有疏漏之处,还望批评指正。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。