一、合并排序(归并排序)概念 / 思想
定义:(引用自"百度百科")
- 合并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
- 合并排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
- 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。合并排序也叫归并排序。
算法步骤:(引用自"菜鸟教程")
- 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
- 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
- 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
- 重复步骤 3 直到某一指针达到序列尾;
- 将另一序列剩下的所有元素直接复制到合并序列尾。
示例图:
二、分治算法实现
1. 设计递归方程
-
我们需要将序列拆分,将当前区间一分为二,即求中间点;
-
递归地对两个子区间 L[left…mid] 和 R[mid+1…right] 进行归并排序(即再次执行第一步);
-
当拆分后的子序列只含有一个元素时,将已排序的两个子区间 L[left…mid] 和 R[mid+1…right] 合并为一个有序的区间[left…right]。
2. 编写程序代码
// 合并排序
#include<iostream>
using namespace std;
void mergeSort(int array[], int left, int right);
void merge(int array[], int left, int mid, int right);
int main()
{
// 待排序数组,也可进行改写,获取键盘输入进行排序
int array[] = { 10,5,8,6,3,9,4,1,2,7 };
int len = sizeof(array) / sizeof(int); // 数组长度
mergeSort(array, 0, len-1);
cout << "合并排序:";
for (int i = 0;i < len;i++)
cout << array[i] << " ";
cout << endl;
return 0;
}
void mergeSort(int array[], int left, int right)
{
// 当子序列就只有一个元素的时候结束递归调用
if (left == right)
return;
else {
// 分治
// 判断中间位置,进行拆分
int mid = (left + right) / 2;
mergeSort(array, left, mid);
mergeSort(array, mid + 1, right);
// 合并
merge(array, left, mid, right);
}
}
void merge(int array[], int left, int mid, int right)
{
// 声明一个指针,指向临时数组,临时存放排序后的元素
int* tempArray = new int[right - left + 1];
int left_1 = left; // 指向 左待排序区域 第一个元素
int left_2 = mid + 1; // 指向 右待排序区域 第一个元素
int k = 0; // 指向 临时数组 第一个元素
// 顺序选取两个待排序区的较小元素,存储到tempArr数组中
while (left_1 <= mid && left_2 <= right) {
// 将较小的元素存入tempArr数组中,并将指针递增
if (array[left_1] <= array[left_2])
tempArray[k++] = array[left_1++];
else
tempArray[k++] = array[left_2++];
}
// 若比较完之后,有序区仍有剩余元素,则直接复制到tempArray数组中
while (left_1 <= mid)
tempArray[k++] = array[left_1++];
while (left_2 <= right)
tempArray[k++] = array[left_2++];
// 将临时数组中排序后的元素取出
for (int i = left, j = 0;i <= right;i++,j++)
array[i] = tempArray[j];
// 删除指针
delete[] tempArray;
}
3. 运行结果展示
4. 程序改进
程序只是举例排序{ 10,5,8,6,3,9,4,1,2,7 },
可以使用cin获取用户输入替代此数组,对用户输入的数据进行排序。
三、自然合并排序
1. 概念 / 基本思想
-
自然合并排序是合并排序算法的一种改进;
-
对于初始给定的数组,通常存在多个长度大于1的已排好序的子数组段。因此用一次线性扫描就可以找出所有这些排好序的子数组段,然后将相邻的排好序的子数组段两两合并。
-
注:通常情况下, 按此方式进行合并排序所需的合并次数较少。
-
举个栗子:
- 数组a中元素为{2, 5, 8, 3, 6, 10, 4, 9};
- 用一次对数组a的线性扫描,找出自然排好序的子数组段:{2, 5, 8},{3, 6},{10},{4, 9};
- 然后将相邻的排好序的子数组段两两合并:{2, 3, 5, 6, 8},{4, 9, 10};
- 继续合并直至整个数组排好序{2, 3, 4, 5, 6, 8, 9, 10}。
2. 编写程序代码
// 待更新。。。
3. 运行结果展示
运行截图(待更新。。。)
三、友情链接~
- 其它一些常见算法请参阅此链接~
最后,非常欢迎大家来讨论指正哦!