二路归并排序的递归写法与迭代写法

1. 问题描述:

对于给定的序列使用二路归并排序算法对其进行排序

2. 思路分析:

① 二路归并排序可以看做是一种分而治之的过程:先将序列分为两半,对每一半分别进行排序之后然后再将其合并起来,而分成的一般又可以使用同样的方法进行排序,之后将会得到一个有序的序列,从上面的描述中我们可以看到问题的规模是在逐渐变小的,而且都是使用相同的办法去解决的,所以第一种方法可以使用递归去解决

② 使用递归的方法去求解那么首先是需要将序列分成两半,然后对分成的两半进行排序,对左右两边排好序的序列进行合并,所以核心的方法是在写将两个有序的序列合并成一个有序序列的方法

③ 在合并的序列的方法中,我们需要传入几个参数,需要传进去左半部分有序部分的起始端点与结束端点,还有就是右半部分有序部分的起始端点与结束端点,需要定义两个指针分别指向的是左半部分区间的起始端点与右半部分的起始端点,使用if判断看一下哪一个元素比较小,这里还需要使用一个额外的数组来存储中间元素,把所有合并的数字存储进一个辅助数组里面,循环的执行条件是左区间和右区间都还没到达区间的尽头,所以有一种情况是一个区间已经到尽头了,另外一个区间还有元素那么元素那么就需要判断一下将剩余的元素加入到这个辅助数组中,最后需要将辅助数组中的元素全部赋值给之前的数组

④ 除了使用上面的递归求解之外我们还可以使用迭代的方法进行求解,其实我们从上面的递归求解的思路中可以看到它是每一次都是分为序列分成两个部分,所以我们在一开始的时候就可以令步长step等于2,然后将数组中每step个元素作为一组,将其内部进行排序,把左边的step / 2与右边的step / 2个元素合并,然后令step 乘以2重复上面的操作,直到step / 2超过元素个数n,我感觉的话使用迭代的方法来做的话可能比较难以理解,我们需要根据具体的例子来确定程序中相应下标的位置

3. 下面是具体的程序代码:

① 递归实现:

#include
const int maxn = 100;
void merge(int A[], int L1, int R1, int L2, int R2){
	int i = L1, j = L2;
	int temp[maxn], index = 0;
	while(i <= R1 && j <= R2){
		if(A[i] <= A[j]){
			temp[index++] = A[i++];
		}else{
			temp[index++] = A[j++];
		}
	}
	while(i <= R1) temp[index++] = A[i++];
	while(j <= R2) temp[index++] = A[j++];
	for(int i = 0; i < index; ++i){
		A[L1 + i] = temp[i];
	} 
}
//将array数组当前的[left, right]进行归并排序
void mergeSort(int A[], int left, int right){
	if(left < right){
		int mid = (left + right) / 2;
		mergeSort(A, left, mid);
		mergeSort(A, mid + 1, right);
		merge(A, left, mid, mid + 1, right);
	}
} 

int main(void){
	int arr[9] = {12, 56, 2, 88, -7, 3, -1, 7, 100};
	mergeSort(arr, 0, 9 );
	for(int i = 0; i < 9; ++i){
		printf("%d ", arr[i]);
	}
	return 0;
}

② 迭代实现,并且数组元素是从下标为0开始的:

#include
#include
#include
using namespace std;
const int maxn = 100;
const int n = 9;
void merge(int A[], int L1, int R1, int L2, int R2){
	int i = L1, j = L2;
	int temp[maxn], index = 0;
	while(i <= R1 && j <= R2){
		if(A[i] <= A[j]){
			temp[index++] = A[i++];
		}else{
			temp[index++] = A[j++];
		}
	}
	while(i <= R1) temp[index++] = A[i++];
	while(j <= R2) temp[index++] = A[j++];
	for(int i = 0; i < index; ++i){
		A[L1 + i] = temp[i];
	} 
}


void mergeSort(int A[]){
	//下面是从下标从0开始的 
	for(int step = 2; step / 2 <= n; step *= 2){
		for(int i = 0; i < n; i += step){
			//step / 2表示的左区间的元素的个数  
			int mid = i + step / 2 - 1;
			if(mid + 1 < n){
				merge(A, i, mid, mid + 1, min(i + step - 1, n - 1));
			}
		}
	}
}

int main(void){
	int arr[9] = {12, 56, 2, 88, -7, 3, -1, 7, 100};
	mergeSort(arr);
	for(int i = 0; i < 9; ++i){
		cout << arr[i] << " ";
	}
	return 0;
}

③ 迭代实现,并且数组元素是从下标为1开始的:

#include
#include
#include
using namespace std;
const int maxn = 100;
const int n = 9;
void merge(int A[], int L1, int R1, int L2, int R2){
	int i = L1, j = L2;
	int temp[maxn], index = 0;
	while(i <= R1 && j <= R2){
		if(A[i] <= A[j]){
			temp[index++] = A[i++];
		}else{
			temp[index++] = A[j++];
		}
	}
	while(i <= R1) temp[index++] = A[i++];
	while(j <= R2) temp[index++] = A[j++];
	for(int i = 0; i < index; ++i){
		A[L1 + i] = temp[i];
	} 
}

void mergeSort(int A[]){
	for(int step = 2; step / 2 <= n; step *= 2){
		for(int i = 1; i <= n; i += step){
			int mid = i + step / 2 - 1;
			if(mid + 1 <= n){
				//使用min函数是为了防止加上step之后可能会出现越界的情况 
				merge(A, i, mid, mid + 1, min(i + step - 1, n));
			}
		}
	}
}

int main(void){
	int arr[10] = {0, 12, 56, 2, 88, -7, 3, -1, 7, 100};
	mergeSort(arr);
	for(int i = 1; i <= 9; ++i){
		cout << arr[i] << " ";
	}
	return 0;
}

 

你可能感兴趣的:(C&&C++,排序)