歸併排序及求小和問題

歸併排序
歸併排序是先將序列的每相鄰的兩個數字進行歸併操作,形成兩兩一對排序好的元素,接着將上述序列再次歸併,形成包含四個元素的序列。重複上述步驟,直到所有元素排序完畢。
歸併排序的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);	
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章