归并排序详解:从合并操作到完整实现(c++)
归并排序核心思想是将数组分成两个子数组,分别对子数组进行排序,然后将排序后的子数组合并成一个有序的数组
归并排序核心思想是将数组分成两个子数组,分别对子数组进行排序,然后将排序后的子数组合并成一个有序的数组。归并排序的时间复杂度为 O(nlogn),空间复杂度为 O(n),并且是一种稳定排序算法
1. 归并排序的基本思想
归并排序的核心思想是分治法。具体步骤如下:
-
分解:将待排序的数组分成两个子数组,分别对这两个子数组进行排序
-
递归:递归地对子数组进行排序,直到子数组的长度为1(此时子数组已经有序)
-
合并:将两个有序的子数组合并成一个有序的数组
归并排序的关键在于合并操作,即将两个有序数组合并成一个有序数组的过程
2. 合并操作
2.1 合并操作的实现
合并操作是归并排序的核心步骤。假设我们有两个已经排好序的数组 a 和 b,我们需要将它们合并成一个有序的数组 c
合并操作的步骤如下:
-
初始化三个指针
i、j、k,分别指向数组a、b、c的起始位置 -
比较
a[i]和b[j],将较小的元素放入c[k],并移动相应的指针 -
重复步骤2,直到其中一个数组的所有元素都被放入
c中 -
将另一个数组中剩余的元素依次放入
c中
以下是合并操作的代码实现:
void merge(int a[], int low, int mid, int hight) {
int b[1000]; // 辅助数组
int i = low, j = mid + 1, k = 0; // i指向左半部分,j指向右半部分,k指向辅助数组
while (i <= mid && j <= hight) {
if (a[i] <= a[j]) // 将较小的元素放入辅助数组
b[k++] = a[i++];
else
b[k++] = a[j++];
}
while (i <= mid) // 将左半部分剩余的元素放入辅助数组
b[k++] = a[i++];
while (j <= hight) // 将右半部分剩余的元素放入辅助数组
b[k++] = a[j++];
k = 0;
for (int i = low; i <= hight; i++) // 将辅助数组中的元素复制回原数组
a[i] = b[k++];
}
2.2 合并操作的时间复杂度
合并操作的时间复杂度为 O(n),其中 n是两个子数组的总长度。因为我们需要遍历两个子数组的所有元素,并将它们合并到一个新的数组中
3. 递归分治
3.1 分治法的基本思想
分治法是一种算法设计思想,它将一个大问题分解成若干个相似的子问题,递归地解决这些子问题,然后将子问题的解合并成原问题的解。归并排序正是利用了分治法的思想。
3.2 归并排序的递归实现
归并排序的递归实现步骤如下:
-
分解:将数组从中间分成两个子数组。
-
递归:对这两个子数组分别进行归并排序。
-
合并:将排序后的两个子数组合并成一个有序的数组。
以下是归并排序的递归实现代码:
void mergesort(int* a, int low, int hight) {
if (low < hight) { // 递归终止条件
int mid = (low + hight) / 2;
mergesort(a, low, mid); // 对左半部分进行归并排序
mergesort(a, mid + 1, hight); // 对右半部分进行归并排序
merge(a, low, mid, hight); // 合并左右两部分
}
}
4. 完整归并排序的实现
4.1 代码实现
以下是完整的归并排序代码实现,包括合并操作和递归分治:
#include<bits/stdc++.h>
using namespace std;
void merge(int a[], int low, int mid, int hight) {
int b[1000]; // 辅助数组
int i = low, j = mid + 1, k = 0; // i指向左半部分,j指向右半部分,k指向辅助数组
while (i <= mid && j <= hight) {
if (a[i] <= a[j]) // 将较小的元素放入辅助数组
b[k++] = a[i++];
else
b[k++] = a[j++];
}
while (i <= mid) // 将左半部分剩余的元素放入辅助数组
b[k++] = a[i++];
while (j <= hight) // 将右半部分剩余的元素放入辅助数组
b[k++] = a[j++];
k = 0;
for (int i = low; i <= hight; i++) // 将辅助数组中的元素复制回原数组
a[i] = b[k++];
}
void mergesort(int* a, int low, int hight) {
if (low < hight) { // 递归终止条件
int mid = (low + hight) / 2;
mergesort(a, low, mid); // 对左半部分进行归并排序
mergesort(a, mid + 1, hight); // 对右半部分进行归并排序
merge(a, low, mid, hight); // 合并左右两部分
}
}
int main() {
int n, a[100];
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
mergesort(a, 0, n - 1);
for (int i = 0; i < n; i++)
cout << a[i] << " ";
return 0;
}
4.2 时间复杂度分析
归并排序的时间复杂度为 O(nlogn)。具体分析如下:
-
分解:每次将数组分成两半,分解的次数为 logn
-
合并:每次合并操作的时间复杂度为 O(n)
-
因此,总的时间复杂度为 O(nlogn)
4.3 空间复杂度分析
归并排序的空间复杂度为 O(n),主要是因为需要一个辅助数组来存储合并后的结果
5. 归并排序的稳定性
归并排序是一种稳定排序算法。稳定性指的是在排序过程中,相等的元素的相对位置不会改变。归并排序在合并操作中,当两个元素相等时,优先选择左边的元素,因此保证了排序的稳定性
6. 归并排序的优缺点
优点:
-
时间复杂度为 O(nlogn),适合处理大规模数据
-
是一种稳定排序算法
缺点:
-
空间复杂度为 O(n),需要额外的存储空间
-
对于小规模数据,归并排序的性能可能不如插入排序等简单排序算法
更多推荐
所有评论(0)