一、算法基本思想
把两个有序序列合并到一起
初始时两个指针i,j分别指向两个序列的首部,比较所指元素的大小,把较小的元素放到下面空序列中,对应指针向后移动。
当一个序列的指针超出范围时把另一个序列的剩余元素直接放到下面的新序列。
二、实现过程
初始序列
设置三个指针low,mid,high,分别指向首部,尾部和中间,mid=(low+high)/2
根据mid把整个序列分为两个
继续分解
分解到最后可以看作是一组组的有序序列,然后进行排序,形成新的有序序列
继续两两合并
最终得到有序序列
三、代码实现
1.对有序序列进行合并
//创建一个指针指向长度为8的数组的首地址
int* temp = (int*)malloc(8 * sizeof(int));
void Merge(int num[], int low, int high, int mid) {
int i, j, k;
//把要排序的数组复制到临时数组
for (k = low; k <= high; k++) {
temp[k] = num[k];
}
//对两个序列进行排序
//如果有一个序列的指针超出范围就跳出循环
for (i = low, j = mid + 1, k = low; i <= mid && j <= high; k++) {
if (temp[i] <= temp[j]) {
num[k] = temp[i];
i++;
}
else {
num[k] = temp[j];
j++;
}
}
//如果一个序列的指针超出范围,把另一个序列的剩余元素直接放到原数组对应位置
while (i <= mid)num[k++] = temp[i++];
while (j <= high)num[k++] = temp[j++];
}
2.对初始序列进行分解和排序
void MergeSort(int num[], int low, int high) {
if (low < high) {
//递归实现序列的分解
int mid = (low + high) / 2;
MergeSort(num, low, mid);
MergeSort(num, mid+1, high);
Merge(num, low, high, mid);
}
}
四、完整代码和运行结果
int* temp = (int*)malloc(8 * sizeof(int));
void Merge(int num[], int low, int high, int mid) {
int i, j, k;
for (k = low; k <= high; k++) {
temp[k] = num[k];
}
for (i = low, j = mid + 1, k = low; i <= mid && j <= high; k++) {
if (temp[i] <= temp[j]) {
num[k] = temp[i];
i++;
}
else {
num[k] = temp[j];
j++;
}
}
while (i <= mid)num[k++] = temp[i++];
while (j <= high)num[k++] = temp[j++];
}
void MergeSort(int num[], int low, int high) {
if (low < high) {
int mid = (low + high) / 2;
MergeSort(num, low, mid);
MergeSort(num, mid+1, high);
Merge(num, low, high, mid);
}
}
int main() {
int num[8] = { 49,38,65,97,76,13,27,49 };
MergeSort(num, 0, 7);
for (int i = 0; i < 8; i++) {
printf("%d\n", num[i]);
}
}
五、算法效率分析
1.空间复杂度
①临时数组的创建,长度为n,空间复杂度为O(n)
②递归栈:所占空间的大小与归并的次数有关
可以把有序序列分别看作是一个完全二叉树的结点,最上层的结点数=序列元素个数=n
二叉树第h层最多有2^(h-1)个结点,若树高为h,则应满足n<=2^(h-1),即h-1>=log₂n
完全二叉树最大高度满足h-1=log₂n,所以归并的趟数是log₂n
所以递归的深度为log₂n,空间复杂度为O(log₂n)
所以空间复杂度=O(log₂n)+O(n)=O(log₂n)(只保留高阶)
2.时间复杂度
每趟归并的时间复杂度为O(n)
共进行了log₂n次归并,所以时间复杂度为O(nlog₂n)