🌈个人主页:羽晨同学
💫个人格言:“成为自己未来的主人~”
归并排序
递归版本
首先,我们来看一下归并的示意图:
这是归并排序当中分解的过程。 然后便是两个两个进行排序,组合的过程。
归并完美的诠释了“分治的思想”,分治分治,分而治之,我们将一个大的问题不断地分为一个个小的子问题,然后通过解决子问题的目的对大问题进行解决。
为了更好的理解,接下来,请看下面的这一张动图:
我们在这张图中可以理解到归并的实现逻辑,它的实现,需要借助一个新的数组,并两个,四个,逐渐进行排序。
- 用malloc函数开辟一个新的数组,并对数组进行检查
- 确定最小子问题(当只有一个元素的时候就不用在进行递归,一个就是有序的)
- 进行递归找到最小子区间(第一张示意图的最后一行)
- 然后其实就是两个有序数组的合并,合并之后再进行拷贝,然后又进行合并,继续拷贝。
首先,我们给到归并排序在.h文件中的定义。
//Sort.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
void MergeSort(int* a, int n);
接下来,我们在.c文件中进行归并排序的实现
首先,我们写一下归并排序的整体框架:
void MergeSort(int* a, int begin, int end, int* tmp)
{//......
}
void MergeSort(int* a, int n)
{//开辟数组int* tmp = (int*)malloc(sizeof(int) * n);if (tmp = NULL){perror("malloc fail");return;}_MergeSort(a, 0, n - 1, tmp);//清除开辟的数组free(tmp);tmp = NULL;
}
接下来,我们在子函数当中,对代码进行完善
#define _CRT_SECURE_NO_WARNINGS
#include"Sort.h"
void _MergeSort(int* a, int begin, int end, int* tmp)
{if (begin == end)return;//定义初始变量int mid = (begin + end) / 2;int begin1 = begin, end1 = mid;int begin2 = mid+1, end2 = end;_MergeSort(a, begin1, end1, tmp);_MergeSort(a, begin2, end2, tmp);int i = begin;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] >= a[begin2]){tmp[i++] = a[begin2++];}else{tmp[i++] = a[begin1++];}}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 (tmp == NULL){perror("malloc fail");return;}_MergeSort(a, 0, n-1, tmp);free(tmp);tmp = NULL;
}
接下来是归并排序的测试代码:
#define _CRT_SECURE_NO_WARNINGS
#include"Sort.h"
int main()
{int a[] = { 5,1,2,7,5,6,2,5,3,9,7 };MergeSort(a, sizeof(a) / sizeof(int));for (int i = 0; i < sizeof(a) / sizeof(int); i++){printf("%d ", a[i]);}return 0;
}
非递归版本
- 我们设置一个gap表示begin1,end1,begin2,end2
- 非递归版本主要就是通过控制gap来实现递归
void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);int gap = 1;while (gap < n){for (int i = 0; i < n; i += 2 * gap){int begin1 = i, end1 = begin1 + gap - 1;int begin2 = begin1 + gap, end2 = begin2 + gap - 1;//if (end1 >= n || begin2 >= n){break;}if (end2 >= n)end2 = n - 1;int j = i;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] >= a[begin2]){tmp[j++] = a[begin2++];}else{tmp[j++] = a[begin1++];}}while (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));}gap *= 2;}}
- 我们先设定一个gap=1(这个代表只有一个元素,这个自然是有序的)
- 然后我们令gap*=2,实现gap的递增,从而扩大排序的范围
对于归并排序而言,
它的时间复杂度是O(N*logN)
它的空间复杂度是O(N)
稳定性:稳定
归并排序的主要缺点就是空间复杂度较大,需要开辟新的空间。
好了,这个就是归并排序的所有内容。
归并排序此外还被用到了文件排序当中,这个我们后面会进行讲解。