[데이터 구조--손 떼기 정렬 알고리즘 7부] 병합 정렬의 재귀적 구현

목차

1. 병합의 아이디어

2. 병합 정렬의 아이디어

2.1 기본 아이디어

2.2 그래픽 분석

3. 병합 정렬 재귀 버전 코드 구현

3.1 코드 분석

3.2 주의사항

3.2.1 잘못된 구분: [begin, mid-1], [mid, end]

3.2.2 올바른 구분: [begin, mid], [mid+1, end]

4. 병합 정렬 테스트

5. 시간복잡도와 공간복잡도 분석

5.1 시간 복잡도

5.2 공간 복잡도


1. 병합의 아이디어

머징의 개념을 이번이 두 번째로 이해하게 되었습니다. 이전 연결 리스트 oj 문제에서 처음으로 순서가 있는 두 개의 링크드 리스트를 병합했습니다. 당시 문제를 해결하려는 우리의 아이디어는 병합.

이번에는 체계적으로 병합하는 아이디어를 연구해 봅시다( 이 기사에서는 오름차순을 예로 들었습니다 ).

두 개의 배열(linked list)을 병합할 때 두 개의 포인터를 사용하여 서로 다른 배열의 첫 번째 요소를 가리키고 두 배열을 제어 및 순회하며 두 포인터가 가리키는 값을 비교합니다. 임시 배열을 만든 다음 포인터를 작은 값의 포인터가 한 단계 뒤로 이동하고 비교가 계속됩니다. 계속 비교해 보면 정렬된 배열이기 때문에 항상 먼저 순회 하는 배열이 있고 순회하지 않은 다른 배열은 임시 배열의 뒷면에 직접 연결하여 정렬을 완료합니다.

이 아이디어를 이해하기 위해 그림을 그려 봅시다.

2. 병합 정렬의 아이디어

2.1 기본 아이디어

병합 정렬은 병합 작업을 기반으로 하는 효율적인 정렬 알고리즘입니다.

1. 병합과 정렬의 개념은 하나의 배열을 좌우 두 개의 배열로 나눈 다음 분할된 하위 범위가 하나의 데이터가 될 때까지 계속해서 왼쪽과 오른쪽 배열을 나누고 데이터가 순서대로 정렬되어야 한다는 것입니다. 이분법.

2. 다음으로 왼쪽 및 오른쪽 하위 간격을 정렬 및 병합하고 연속적으로 정렬 및 병합하여 최종적으로 전체 배열의 정렬을 실현합니다.

2.2 그래픽 분석

병합할 때 원본 어레이에서 직접 교환하지 않고 원본 어레이에서 직접 작업하면 덮어쓰기오류가 발생합니다 . 따라서 원래 배열과 같은 크기의 공간 tmp를 malloc하고 각 병합 후 값을 tmp로 복사하고 병합 및 복사를 한 번 수행하면 중간 tmp 배열이 순서대로 된 다음 memcpy를 사용하여 tmp를 원래 배열로 다시 복사합니다. 그런 다음 free(tmp)(메모리 누수를 방지하기 위해) 전체 정렬이 완료됩니다.

3. 병합 정렬 재귀 버전 코드 구현

// 归并排序递归实现
// 时间复杂度:O(N*logN)
// 空间复杂度:O(N + logN)
void _MergeSort(int* a, int begin, int end, int* tmp)
{
	if (begin >= end)
		return;

	int mid = (begin + end) / 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 <= 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 + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}
void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (NULL == tmp)
	{
		perror("malloc fail:");
		return;
	}
	_MergeSort(a, 0, n-1, tmp);
	free(tmp);
}
 
 

3.1 코드 분석

우리는 이 절에서 재귀를 사용했는데 재귀의 개념은 배열을 좌우 간격으로 나눈 다음 계속해서 왼쪽과 오른쪽 간격을 나누는 것입니다. 정렬+병합을 진행합니다.

이 섹션은 정렬 + 병합입니다. 우리는 두 개의 하위 간격을 정렬 + 병합합니다. 아이디어는 병합에 대한 우리의 아이디어입니다. 여기서 주의할 점은 우리 tmp의 첨자가 begin이라는 점에 유의해야 하는데, 이는 각 레이어의 병합된 값을 먼저 tmp에 넣은 후 원래 배열에 복사해야 하기 때문이며, 0이면 다시 복사할 때 오류가 발생합니다 . .

3.2 주의사항

좌우간격을 나눌때 반드시 [begin, mid], [mid+1, end],

[begin, mid-1], [mid, end]가 될 수 없습니다! ! !

여기서 실수하기 쉬우니 논리상으로는 문제가 없을 것 같지만 정렬할 때 문제가 있을 것입니다.

3.2.1 오류 구분: [begin, mid-1], [mid, end]

3.2.2 올바른 구분: [begin, mid], [mid+1, end]

요약: 무한 루프의 첫 번째 나눗셈에 대한 이유는 mid = begin+end/2일 때 계산기가 내림되기 때문에 내림되면 간격에 중간 값이 포함되어야 합니다. 내림으로.

4. 병합 정렬 테스트

void Print(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}
void _MergeSort(int* a, int begin, int end, int* tmp)
{
	if (begin >= end)
		return;

	int mid = (begin + end) / 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 <= 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 + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}
void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (NULL == tmp)
	{
		perror("malloc fail:");
		return;
	}
	_MergeSort(a, 0, n - 1, tmp);

	free(tmp);
}
void test()
{
	int a[] = { 6,3,2,1,5,7,9 };
	Print(&a, sizeof(a) / sizeof(int));
	MergeSort(&a, sizeof(a) / sizeof(int) - 1);
	Print(&a, sizeof(a) / sizeof(int));
}
int main()
{
	test();

	return 0;
}
 
 

시험 결과:

5. 시간복잡도와 공간복잡도 분석

5.1 시간 복잡도

머지와 소트 구간을 연속적으로 나누어 시간복잡도는 O(logN), 다시 머지하면 시간복잡도는 O(N)이다.

전체 시간 복잡도는 o(N*logN)입니다.

5.2 공간 복잡도

정렬을 위한 임시 공간을 열었기 때문에 공간 복잡도는 O(N)입니다.

추천

출처blog.csdn.net/Ljy_cx_21_4_3/article/details/131763637