[数据结构]排序之 归并排序(有详细的递归图解)
一、非递归
基本思想:
归并排序(
MERGE-SORT
)是建立在归并操作上的一种有效的排序算法
,
该算法是采用分治法(
Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 归并排序核心步骤:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
void _MergeSort(int* a, int begin, int end, int* temp)
{
if (begin>=end)
return;
int mid = (begin + end) / 2;
//[begin,mid] [mid+1,end]如果这两个区间有序,那么可以归并了
_MergeSort(a, begin, mid, temp);
_MergeSort(a, mid+1, end, temp);
//[begin, mid] [mid + 1, end]归并
int begin1 = begin, end1 = mid;
int begin2 = mid+1, end2 = end;
int i = begin;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
temp[i] = a[begin1];
i++;
begin1++;
}
else
{
temp[i] = a[begin2];
i++;
begin2++;
}
}
//谁没结束谁++来拷贝,由于不知道是哪个区间没有结束,所有都写一遍
while (begin1 <= end1)
{
temp[i] = a[begin1];
i++;
begin1++;
}
while (begin2 <= end2)
{
temp[i] = a[begin2];
i++;
begin2++;
}
//等把所有数都放到temp数组上时,再拷贝回去
memcpy(a+begin, temp+begin,sizeof(int)*(end-begin+1));
}
void MergeSort(int* a, int n)
{
int* temp = (int*)malloc(sizeof(int) * n);
if (temp == NULL)
{
perror("malloc fail\n");
return;
}
_MergeSort(a, 0, n - 1, temp);
free(temp);
}
int main()
{
int a[] = {10,6,7,1,3,9,4,2 };
MergeSort(a,8);
for (int i = 0; i < 8; i++)
{
printf("%d ", a[i]);
}
return 0;
}
注:以下图片看不清楚可以点进去放大看
二、递归
不能用栈,栈是前序,而归并是后序
方法:
能不能依次依次往后算?算完第一个和第二个后算第三个和第四个,再算第五个和第六个.......
第一次归完后再拷贝回去后四个四个一归.....

必须得注意细节:如果是奇数个数那么得注意边界
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
void Swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void _MergeSort(int* a, int begin, int end, int* temp)
{
if (begin >= end)
return;
int mid = (begin + end) / 2;
//[begin,mid] [mid+1,end]如果这两个区间有序,那么可以归并了
_MergeSort(a, begin, mid, temp);
_MergeSort(a, mid + 1, end, temp);
//[begin, mid] [mid + 1, end]归并
int begin1 = begin, end1 = mid;
int begin2 = mid + 1, end2 = end;
int i = begin;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
temp[i] = a[begin1];
i++;
begin1++;
}
else
{
temp[i] = a[begin2];
i++;
begin2++;
}
}
//谁没结束谁++来拷贝,由于不知道是哪个区间没有结束,所有都写一遍
while (begin1 <= end1)
{
temp[i] = a[begin1];
i++;
begin1++;
}
while (begin2 <= end2)
{
temp[i] = a[begin2];
i++;
begin2++;
}
//等把所有数都放到temp数组上时,再拷贝回去
memcpy(a + begin, temp + begin, sizeof(int) * (end - begin + 1));
}
void MergeSort(int* a, int n)
{
int* temp = (int*)malloc(sizeof(int) * n);
if (temp == NULL)
{
perror("malloc fail\n");
return;
}
int gap = 1;
while (gap < n)
{
for (int i = 0; i < n; i += 2 * gap)
{
int begin1 = i, end1 = i + gap - 1;
int begin2 = i + gap, end2 = i + 2 * gap - 1;
int j = i;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
temp[j] = a[begin1];
j++;
begin1++;
}
else
{
temp[j] = a[begin2];
j++;
begin2++;
}
}
//谁没结束谁++来拷贝,由于不知道是哪个区间没有结束,所有都写一遍
while (begin1 <= end1)
{
temp[j] = a[begin1];
j++;
begin1++;
}
while (begin2 <= end2)
{
temp[j] = a[begin2];
j++;
begin2++;
}
//等把所有数都放到temp数组上时,再拷贝回去
memcpy(a + begin, temp + begin, sizeof(int) * (end - begin + 1));
}
gap *= 2;
}
free(temp);
}
int main()
{
int a[] = {10,6,7,1,3,9,4,2 };
MergeSort(a,8);
for (int i = 0; i < 8; i++)
{
printf("%d ", a[i]);
}
return 0;
}