几个高级排序算法之一,具体原理可以参考这个视频:归并排序算法讲解。基本原理就是使用分治的思想,将数组不断二分,分割成单个元素,然后从单个元素开始两两合并,将两个有序的数组片段合并为一个新的有序片段。最后将整个数组归为有序。
基本步骤:
由上面的过程,知道归并排序需要使用递归来完成,先分割,分割到最底层了,然后开始合并。
因此递归函数可以这样写:
void MergeSort(vector& nums, int start, int end, vector& tmp) {
if (nums.empty() || start >= end)return;
int mid = start + (end - start) / 2;
//将待排序区间从中间分割开
MergeSort(nums, start, mid, tmp);
MergeSort(nums, mid + 1, end, tmp);
//将分割开的元素进行合并
Merge(nums, start, mid, end, tmp);
}
其中Merge()函数是核心,负责将两个片段进行合并。Merge()函数中需要先将两个片段拷贝一份,然后按顺序将两个片段的内容写到源地址上。
/**实现具体归并的函数
*
*该函数将两个有序的数组进行合并,合并为一个有序的数组
*传入参数:第一个已排序序列[start, mid];第二个已排序序列[mid+1, end];临时存储数组tmp
*/
void Merge(vector& nums, int start, int mid, int end, vector& tmp) {
int firstIdx = start;
int secondIdx = mid + 1;
int numsIdx = start;
//先将两个已排序序列复制到tmp中
for (int i = start; i <= mid; ++i)tmp[i] = nums[i];
for (int i = mid + 1; i <= end; ++i)tmp[i] = nums[i];
//然后将tmp中的两段数组合并到nums中
while (numsIdx <= end) {
if (secondIdx > end)nums[numsIdx++] = tmp[firstIdx++];
else if (firstIdx > mid)nums[numsIdx++] = tmp[secondIdx++];
else {
if (tmp[firstIdx] <= tmp[secondIdx])nums[numsIdx++] = tmp[firstIdx++];
else nums[numsIdx++] = tmp[secondIdx++];
}
}
}
带输入的完整程序如下:
// MergeSort_Vector.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include
#include
using namespace std;
void Sort(vector& nums);
void MergeSort(vector& nums, int start, int end, vector& tmp);
void Merge(vector& nums, int start, int mid, int end, vector& tmp);
void printArray(vector& nums);
int main()
{
vector a({ 5,6,1,8,3,4,9,7,2,3 });
//打印a的初始值
cout << "Initial value of vecotr a:";
printArray(a);
Sort(a);
//打印排序后的a
cout << "Sorted value of vecotr a:";
printArray(a);
return 0;
}
//通用接口
void Sort(vector& nums) {
vector tmp(nums.size());
MergeSort(nums, 0, nums.size() - 1, tmp);
}
//归并排序的入口
void MergeSort(vector& nums, int start, int end, vector& tmp) {
if (nums.empty() || start >= end)return;
int mid = start + (end - start) / 2;
//将待排序区间从中间分割开
MergeSort(nums, start, mid, tmp);
MergeSort(nums, mid + 1, end, tmp);
//将分割开的元素进行合并
Merge(nums, start, mid, end, tmp);
}
/**实现具体归并的函数
*
*该函数将两个有序的数组进行合并,合并为一个有序的数组
*传入参数:第一个已排序序列[start, mid];第二个已排序序列[mid+1, end];临时存储数组tmp
*/
void Merge(vector& nums, int start, int mid, int end, vector& tmp) {
int firstIdx = start;
int secondIdx = mid + 1;
int numsIdx = start;
//先将两个已排序序列复制到tmp中
for (int i = start; i <= mid; ++i)tmp[i] = nums[i];
for (int i = mid + 1; i <= end; ++i)tmp[i] = nums[i];
//然后将tmp中的两段数组合并到nums中
while (numsIdx <= end) {
if (secondIdx > end)nums[numsIdx++] = tmp[firstIdx++];
else if (firstIdx > mid)nums[numsIdx++] = tmp[secondIdx++];
else {
if (tmp[firstIdx] <= tmp[secondIdx])nums[numsIdx++] = tmp[firstIdx++];
else nums[numsIdx++] = tmp[secondIdx++];
}
}
}
//vector的打印函数
void printArray(vector& nums) {
for (auto it = nums.begin(); it != nums.end();++it)cout << *it << " ";
cout << endl;
}
使用函数模板可以将上面的针对int类型的归并排序拓展到不同的数据类型,使用函数对象可以将自定义的比较函数传入归并排序的算法中,实现对自定义数据类型的排序。对于基本数据类型,可以使用STL中自带的less和greater函数对象。
对排序函数进行重载,对基本数据类型,不传入比较函数的情况下,默认使用STL的less,即实现升序排序。
完整代码如下:
// MergeSort_Vector_Template.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include
#include
#include
using namespace std;
template //通用接口
void Sort(vector& nums, _compare cmp );
template //通用接口,重载,默认使用less作为比较函数
void Sort(vector& nums);
template //归并排序的入口
void MergeSort(vector& nums, int start, int end, vector& tmp, _compare cmp);
template //实现具体归并的函数
void Merge(vector& nums, int start, int mid, int end, vector& tmp, _compare cmp);
template //vector的打印函数
void printArray(vector& nums);
//自定义仿函数,作为比较函数
template
struct cmp {
bool operator()(T& a, T& b) {
return a < b;
}
};
int main()
{
vector a({ 5,6,1,8,3,4,9,7,2,3 });
vector b({"hello","world","hahaha", "welcome", "goodbye","nice","apple" });
//打印a和b的初始值
cout << "Initial value of vecotr a:";
printArray(a);
cout<< "Initial value of vecotr b:";
printArray(b);
//使用STL中的比较函数,less:升序排列;greator:降序排列
Sort(a,less());
//使用自定义的比较函数,可以支持自定义数据类型(或者针对自定义数据类型,重载"<"或">"运算符,可以使用less或者greater
Sort(b, cmp());
//打印排序后的a和b
cout << "Sorted value of vecotr a:";
printArray(a);
cout << "Sorted value of vecotr b:";
printArray(b);
return 0;
}
//通用接口
template
void Sort(vector& nums, _compare cmp) {
vector tmp(nums.size());
MergeSort(nums, 0, nums.size() - 1, tmp, cmp);
}
//重载的带默认比较函数的排序
template
void Sort(vector& nums) {
vector tmp(nums.size());
MergeSort(nums, 0, nums.size() - 1, tmp, less());
}
//归并排序的入口
template
void MergeSort(vector& nums, int start, int end, vector& tmp, _compare cmp) {
if (nums.empty() || start >= end)return;
int mid = start + (end - start) / 2;
//将待排序区间从中间分割开
MergeSort(nums, start, mid, tmp, cmp);
MergeSort(nums, mid + 1, end, tmp, cmp);
//将分割开的元素进行合并
Merge(nums, start, mid, end, tmp, cmp);
}
/**实现具体归并的函数
*
*该函数将两个有序的数组进行合并,合并为一个有序的数组
*传入参数:第一个已排序序列[start, mid];第二个已排序序列[mid+1, end];临时存储数组tmp
*/
template
void Merge(vector& nums, int start, int mid, int end, vector& tmp, _compare cmp) {
int firstIdx = start;
int secondIdx = mid + 1;
int numsIdx = start;
//先将两个已排序序列复制到tmp中
for (int i = start; i <= mid; ++i)tmp[i] = nums[i];
for (int i = mid + 1; i <= end; ++i)tmp[i] = nums[i];
//然后将tmp中的两段数组合并到nums中
while (numsIdx <= end) {
if (secondIdx > end)nums[numsIdx++] = tmp[firstIdx++];
else if (firstIdx > mid)nums[numsIdx++] = tmp[secondIdx++];
else {
if (cmp(tmp[firstIdx], tmp[secondIdx]))nums[numsIdx++] = tmp[firstIdx++];
else nums[numsIdx++] = tmp[secondIdx++];
}
}
}
//vector的打印函数
template
void printArray(vector& nums) {
for (auto it = nums.begin(); it != nums.end(); ++it)cout << *it << " ";
cout << endl;
}