手撕递归归并排序和非递归排序

文章目录

  • 1:递归归并算法思路
    • 代码实现
  • 2:非递归手撕归并排序
  • 3:计数排序

1:递归归并算法思路

手撕递归归并排序和非递归排序_第1张图片

思路:n个数字,每次对半分,直到每组元素只有1个,每次排序排前半段,然后排后半段,因此就有4个变量。

int begin1 = begin, end1 = mid;
int begin2 = mid + 1, end2 = end;
//begin代表整个数组的首元素下标,end表示末尾元素下标,mid表示end-begin的一半表示中间元素的下标。

手撕递归归并排序和非递归排序_第2张图片

如图所示

代码实现

_MergeSort(int* a, int begin,int end,int* tmp)
{
	if (begin >= end)
	{
		return;
	}	
	int mid = (end + begin) / 2;
	//[begin,mid][mid+1,end]
	_MergeSort(a, begin, mid, tmp);
	_MergeSort(a, mid+1, end, tmp);
	int begin1 = begin, end1 = mid;
	int begin2 = mid + 1, end2 = end;
	int i = begin;
	while (begin1 <= end && begin2 <= end2)
	{
		if (a[begin1] <= a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}
	memcpy(a + begin, tmp + begin, sizeof(a) * (end - begin + 1));

}
void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int)*n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	_MergeSort(a, begin, end, tmp);

}

2:非递归手撕归并排序

void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int)*n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}

	int gap = 1;
	while (gap < n)
	{
		// gap个数据  gap个数据归并
		for (int j = 0; j < n; j += 2 * gap)
		{
			int begin1 = j, end1 = j + gap - 1;
			int begin2 = j + gap, end2 = j + 2 * gap - 1;

			// 第一组越界
			if (end1 >= n)
			{
				printf("[%d,%d]", begin1, n-1);
				break;
			}

			// 第二组全部越界
			if (begin2 >= n)
			{
				printf("[%d,%d]", begin1, end1);
				break;
			}

			// 第二组部分越界
			if (end2 >= n)
			{
				// 修正一下end2,继续归并
				end2 = n - 1;
			}

			printf("[%d,%d][%d,%d] ", begin1, end1, begin2, end2);

			int i = j;
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] <= a[begin2])
				{
					tmp[i++] = a[begin1++];
				}
				else
				{
					tmp[i++] = a[begin2++];
				}
			}

			while (begin1 <= end1)
			{
				tmp[i++] = a[begin1++];
			}

			while (begin2 <= end2)
			{
				tmp[i++] = a[begin2++];
			}

			// 拷贝回原数组
			memcpy(a+j, tmp+j, (end2-j+1)*sizeof(int));
		}

		gap *= 2;
		printf("\n");
	}

	free(tmp);
	tmp = NULL;
}

手撕递归归并排序和非递归排序_第3张图片

而因为会发生越界,所以每次拷贝已经归并的数即可。

3:计数排序

<有一个题目:数组中存储1-n的数字,寻找缺少的某一个数字。>,题解是用兔笼思想,如果n存在就让数组下标n的地方+1,如果发现某个位置是0,那么就找到了这个数字。

手撕递归归并排序和非递归排序_第4张图片

你可能感兴趣的:(算法,排序算法,数据结构)