排序算法四-----归并排序

归并排序
思想:
1、先对数据的整体进行划分:把数据划分为左右均等的两部分,继续划分,直到数据分组有序为止;

2、每个分组只剩下一个元素则是有序的
3、把两个部分(数据)归并成一个部分:逐次归并:给定一个辅助空间,给定一个指针放在第一个数组的起始位置x1,给定另一个指针放在另一个数组的起始位置x2,给定第三个指针放在辅助空间的位置x3比较x1和x2,将较小的元素搬移到辅助空间中,把刚刚较小的那个元素的指针向该数组的下一个位置移动。x3向后走一步,继续比较x1和x2,并搬移元素。


实现代码
//合并需要给定两个数组的空间及辅助空间
void MergeData(int *array, int left, int mid,int right,int *tmp)
{
	//计算出空间的范围
	int beginL = left;//左边的左边界
	int endL= mid;//左边的右边界
	int beginR = mid;//右边的左边界
	int endR = right;//右边的右边界
	int index = left;//临时空间的起始位置
	while (beginL < endL&&beginR < endR)//左边界中有数据,右边界中有数据
	{
		if (array[beginL] < array[beginR])
			//搬到辅助空间里去
			tmp[index++] = array[beginL++];
		else
			tmp[index++] = array[beginR++];
	}
	//左边的数据没有搬移完
	while (beginL < endL)
	{
		tmp[index++] = array[beginL++];
	}
	//右边的数据没有搬移完
	while (beginR < endR)
	{
		tmp[index++] = array[beginR++];
	}

}
void _MergeSort(int *array, int left, int right, int *tmp)
{
	if (right-left>1)//只剩下一个元素则不进行划分
	{
		int mid = left + ((right - left) >> 1);
		//递归进行划分
		//排左边
		_MergeSort(array, left, mid, tmp);
		//排右边
		_MergeSort(array, mid, right, tmp);
		//将两个分组归并成一个分组,放入临时空间里
		MergeData(array, left, mid, right, tmp);
		//把临时空间里面的数据拷贝至待排序的空间中去
		memcpy(array + left, tmp + left, sizeof(array[0])*(right - left));
	}
}
void MergeSort(int *array, int size)
{
	//申请辅助空间
	int *tmp = (int *)malloc(size*sizeof(array[0]));
	if (NULL == tmp)
	{
		assert(0);
		return;
	}
	//排序
	_MergeSort(array, 0, size,tmp);
	//释放空间
	free(tmp);
}

时间复杂度:每层需要O(n),平衡树,深度为lgN所以时间复杂度为O(nlgN);没有最好和最差的场景
空间复杂度:O(n):借助了一个辅助空间

稳定性:稳定的,相邻元素归并在一起,不可能出现跨区间交换……
适用于:数据量比较大,一次加载不了的数据(外部排序)
4、非递归的方式实现(也需要辅助空间)

//合并需要给定两个数组的空间及辅助空间
void MergeData(int *array, int left, int mid, int right, int *tmp)
{
	//计算出空间的范围
	int beginL = left;//左边的左边界
	int endL = mid;//左边的右边界
	int beginR = mid;//右边的左边界
	int endR = right;//右边的右边界
	int index = left;//临时空间的起始位置
	while (beginL < endL&&beginR < endR)//左边界中有数据,右边界中有数据
	{
		if (array[beginL] < array[beginR])
			//搬到辅助空间里去
			tmp[index++] = array[beginL++];
		else
			tmp[index++] = array[beginR++];
	}
	//左边的数据没有搬移完
	while (beginL < endL)
	{
		tmp[index++] = array[beginL++];
	}
	//右边的数据没有搬移完
	while (beginR < endR)
	{
		tmp[index++] = array[beginR++];
	}

}
void MergeSortNor(int *array, int size)
{
	int gap = 1;
	int i = 0;
	//申请辅助空间
	int *tmp = (int *)malloc(size*sizeof(array[0]));
	if (NULL == tmp)
	{
		assert(0);
		return;
	}
	while (gap<size)//gap==size为一个分组,也不用处理
	{
		for (i = 0; i < size; i += 2 * gap)//i+=2*gap:第一次归并第0个和第1个,第二次归并第2个和第三个……两两归并
		{
			//计算区间
			int left = i;
			int mid = left + gap;
			int right = mid + gap;
			//归并
			if (mid > size)//防止mid越界
				mid = size;
			if (right > size)//防止right越界
				right = size;
			MergeData(array, left, mid, right, tmp);
		}
		//将元素拷回去
		memcpy(array, tmp, size*sizeof(array[0]));
		//归并下一次的数据
		gap *= 2;
 	}
	free(tmp);
}


猜你喜欢

转载自blog.csdn.net/xuruhua/article/details/80536700