归并排序:即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并
首先对于一组数据:15 ,2, 35, 6, 23, 11.其中的每一个数据,单个有序。然后,再进行排序使得两个两个数据有序。以此类推进行排序。假设有如下数据,经过第一次排序比较之后:
在上图中的,s1,e1,s2,e2 均代表每一个归并段的起始和结尾。二路归并,一个一个有序归并为两个两个有序。
操作:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾将另一序列剩下的所有元素直接复制到合并序列尾
时间复杂度:O(nlog2n)
空间复杂度:O(n)
稳定性:稳定
void Merge(int *arr, int len, int gap)
{
int *brr = (int*)malloc(sizeof(int)*len);
assert(brr != NULL);
int i = 0;//brr下标
int s1 = 0;
int e1 = s1 + gap - 1;
int s2 = e1 + 1;
int e2 = s2 + gap - 1 < len - 1 ? s2 + gap - 1 : len-1;
//当有两个归并段
while (s2 < len)
{
//两个归并段还没完
while (s1 <= e1&&s2 <= e2)
{
if (arr[s1] <= arr[s2])
{
brr[i++] = arr[s2++];
}
else
{
brr[i++] = arr[s1++];
}
}
//s1完了,s2没完
while (s1 <= e1)
{
brr[i++] = arr[s1++];
}
while (s2 <= e2)
{
brr[i++] = arr[s2++];
}
s1 = e2 + 1;
e1 = s1 + gap - 1;
s2 = e1 + 1;
e2 = s2 + gap - 1 < len - 1 ? s2 + gap - 1 : len - 1;
}
//有一个归并段没处理
while (s1 < len )
{
brr[i++] = arr[s1++];
}
for (int i = 0; i < len; i++)
{
arr[i] = brr[i];
}
}
void MergeSort(int *arr, int len)
{
for (int i = 1; i < len; i *= 2)
{
Merge(arr, len, i);
}
}