归并排序
归并排序是先将序列的每相邻的两个数字进行归并操作,形成两两一对排序好的元素,接着将上述序列再次归并,形成包含四个元素的序列。重复上述步骤,直到所有元素排序完毕。
归并排序的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);
}