归并排序
首先将所有数据默认每个数据单独分成一个组,接下来两两合并,当所有数据在同一个组内,则排序完成。
排序规则
- 将所有数据单独给每个数每个组(每个数据单独看,就是有序的)
- 然后将数据进行两两合并成一组,对每一组数据进行排序
- 然后继续把数据两两合并排序,直到只有一组数据
原始数据: 84 9 18 19 48 12 90 84 90 12
第一次两两合并: 9 84 18 19 12 48 84 90 8 12
第二次两两合并:9 18 19 84 12 48 84 90 8 12
第三次两两合并:9 12 18 19 48 84 84 90 8 12
第四次两两合并:8 9 12 12 18 19 48 84 84 90
代码实现
//二路归并排序
//一次合并函数
void Merge(int* arr, int len, int gap)
{
int* brr = (int*)malloc(sizeof(int) * len);
assert(brr != NULL);
int low1 = 0;
int high1 = low1 + gap - 1;
int low2 = high1 + 1;
int high2 = low2 + gap - 1 < len ? low2 + gap - 1 : len - 1;
int i = 0; //指向辅助空间下标
while (low2 < len) //确保左右两个组都有数据
{
while (low1 <= high1 && low2 <= high2)//保证两个组内都有数据去比较
{
if (arr[low1] <= arr[low2])
{
brr[i++] = arr[low1++];
}
else
{
brr[i++] = arr[low2++];
}
}
//此时肯定有一个组为空,需要判断哪个组为空,需要做对应的处理
//
while (low1 <= high1)
{
brr[i++] = arr[low1++];
}
while (low2 <= high2)
{
brr[i++] = arr[low2++];
}
// 此时应该继续往后选取两个组
low1 = high2 + 1;
high1 = low1 + gap - 1;
low2 = high1 + 1;
high2 = low2 + gap - 1 < len ? low2 + gap - 1 : len - 1;
}
//此时最外层循环退出,此时有两种可能性:前一个组有数据,后一个组空;要么两个组都没有数据
while (low1 < len)
{
brr[i++] = arr[low1++];
}
//最后将brr数据放到原数组中
for (int i = 0; i < len; i++)
{
arr[i] = brr[i];
}
free(brr);
}
void MergeSort(int* arr, int len)
{
for (int i =1;i<len;i*=2)
{
Merge(arr, len, i);
}
}
测试
算法复杂度分析
时间复杂度:
O
(
n
⋅
log
n
)
O(n\cdot \log n )
O(n⋅logn) 由于一次合并函数需要n次,一共需要$\log n $ 次
空间复杂度:
O
(
n
)
O(n)
O(n) 每一次分组排序,需要借助n个辅助空间