Merge sort recursive and non-recursive

Basic idea

Merge sort (MERGE-SORT) is an effective sorting algorithm based on merge operations. This algorithm is a very typical application of the divide and conquer method (Divide and Conquer). Merge the already ordered subsequences to obtain a completely ordered sequence; that is, first make each subsequence orderly, and then make the subsequence segments orderly. If two ordered lists are merged into one ordered list, it is called a two-way merge. Core steps of merge sort:

0f1d3fcc5e85076ed0445cba68d5cb7c.png

 Merge sort is actually to divide the array into equal parts, until the divided array is in order, then merge the two divided arrays into a new array, and then copy them to the original array. This is very similar to the post-order traversal of a binary tree. When the divided array has only one number, it is ordered by default, and then recursively goes back step by step after merging. 

Code (recursive)

void _MergeSort(int* arr, int left, int right,int* tmp)
{
	if (left == right)//不可能分割出不存在的区间
		return;
	int midi = (left + right) / 2;
	_MergeSort(arr, left, midi, tmp);//分割归并左部分
	_MergeSort(arr, midi + 1, right, tmp);//分割归并右部分

	//归并(begin1和end2之间的数)即left和right之间的数
	int i = 0;//临时数组下标
	int begin1 = left, end1 = midi;
	int begin2 = midi + 1, end2 = right;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (arr[begin1] < arr[begin2])
			tmp[i++] = arr[begin1++];
		else
			tmp[i++] = arr[begin2++];
	}
	while (begin1 <= end1)
	{
		tmp[i++] = arr[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = arr[begin2++];
	}

	memcpy(arr+left, tmp, sizeof(int) * i);//归并一次就拷贝一次

}
void MergeSort(int* arr, int left, int right)
{
	int* tmp = (int*)malloc(sizeof(int*) * (right + 1));
	_MergeSort(arr, 0, right,tmp);
	free(tmp);
}

Code 1 (non-recursive)

void _MergeSort(int* arr, int left, int right, int* tmp)
{

	int gap = 1;//每一组的数据个数
	while (gap < right)
	{
		
		for (int i = 0; i <= right; i += 2 * gap)//两两归并,遍历整个数组
		{
			int j = 0;//临时数组的下标
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;

			if (end1 > right || begin2 > right)
				break;
			if (end2 > right)
			{
				end2 = right;
			}

			while (begin1 <= end1 && begin2 <= end2)
			{
				if (arr[begin1] < arr[begin2])
					tmp[j++] = arr[begin1++];
				else
					tmp[j++] = arr[begin2++];
			}
			while (begin1 <= end1)
			{
				tmp[j++] = arr[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[j++] = arr[begin2++];
			}
			memcpy(arr + i, tmp, sizeof(int) * j);//归并一次拷贝一次
		}
		gap *= 2;
	}

}

To be non-recursive, you need to know how the original recursion of the code works. The recursive part is actually divided into two parts. When it can no longer be divided, it starts to be merged into the tmp temporary array, so the non-recursive way of writing is actually It is also executed in groups. First, a single number is a group, and two by two groups are compared and copied. The originally copied can be a group. At this time, each group has two numbers in order, and then two by two groups. The two groups are copied again. At this time, the copied group has four ordered numbers, and then the group of four and four is copied...

However, there may be out-of-bounds situations. Two sets of data copies are very likely to go out of bounds, and there are three out-of-bounds situations:

5eab0d1a341845ad83c158eeff837332.png

 The above one and two situations can be regarded as one: there is a redundant group that is already ordered (less than one group). At this time, the group is already ordered, so there is no need to merge it, and it is placed directly in the original array. That's fine, but when you memcpy the array, you have to copy groups of groups. You can't merge the entire array and then copy it all to the original array.

The third situation is that there are more than one set of data but not enough two sets. At this time, it cannot be said that this set is in order, so the interval is re-divided, and end2 points to the subscript of the last number. , treat these half groups as a group, and copy the data in pairs into order.

Code 2 (non-recursive) 

void _MergeSort(int* arr, int left, int right, int* tmp)
{
	int gap = 1;//每一组的数据个数
	while (gap < right)
	{
		int j = 0;//临时数组下标
		for (int i = 0; i <= right; i += 2 * gap)//两两归并整个数组
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
			if (end1 > right)
			{
				end1 = right;
				begin2 = end2 + 1;//不存在的区间
			}
			else if(begin2 > right)
			{
				begin2 = end2 + 1;//不存在的区间
			}
			else if (end2 > right)
			{
				end2 = right;
			}
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (arr[begin1] < arr[begin2])
					tmp[j++] = arr[begin1++];
				else
					tmp[j++] = arr[begin2++];
			}
			while (begin1 <= end1)
			{
				tmp[j++] = arr[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[j++] = arr[begin2++];
			}
		}
		memcpy(arr, tmp, sizeof(int) * j);//一次拷贝整个数组数据
		gap *= 2;
	}

}

This is the case where the entire array can be copied at once, that is, when an out-of-bounds situation is encountered, the range is adjusted and the copy is continued.

0beea402e2354a38b54fa0cf27fc5fae.jpeg

Guess you like

Origin blog.csdn.net/C_Rio/article/details/131735653