这次仍然是归并排序,在此基础上做了一点点的改进:对小数量的数组用插入排序代替。所以在运行归并排序之前,要先生成小的数组来比较插入排序和归并排序,确定数组大小在小于多少的时候使用插入排序。由于不同机器存在差异,而且排序速度与原始数组也有关,因此我的预设值为1000,步长为100,在我的机器上运行小于1200的数组用插入排序。
程序中包含插入、选择、冒泡排序的算法,并也设有这几种O(n^2)排序算法速度的比较。我会在下次博客中给出快速排序以及一些线性排序的算法。
//Sort.h
#include <fstream>
#include <iostream>
#include <random>
#include <limits>
#include <chrono>
using namespace std;
using namespace std::chrono;
namespace my
{
template <typename T>
void MergeSort(T* A, int p, int r)//将A数组的第p到第r号元素归并排序
{
if (p < r)
{
int q = (p + r) / 2;
MergeSort(A, p, q);
MergeSort(A, q + 1, r);
Merge(A, p, q, r);
}
}
template <typename T>
void MergeSort(T* A, int siz)//对包含siz个数的A数组归并排序
{
MergeSort<T>(A, 0, siz - 1);
}
template <typename T>
void Merge(T* A, int p, int q, int r)//归并程序,不可从外部直接调用
{
int n1 = q - p + 1, n2 = r - q;
T *L = new T[n1 + 1], *R = new T[n2 + 1];
for (int i = 0; i < n1; i++) L[i] = A[p + i];
for (int i = 0; i < n2; i++) R[i] = A[q + i + 1];
L[n1] = numeric_limits<T>::max();
R[n2] = numeric_limits<T>::max();
int i = 0, j = 0;
for (int k = p; k <= r; k++)
if (L[i] < R[j]) A[k] = L[i++];
else A[k] = R[j++];
delete[] L, R;
}
template <typename T>
void MergeSortWithoutSoilder(T* A, int p, int r)//将A数组的第p到第r号元素归并排序,这里没有设置哨兵
{
if (p < r)
{
int q = (p + r) / 2;
MergeSortWithoutSoilder(A, p, q);
MergeSortWithoutSoilder(A, q + 1, r);
MergeWithoutSoilder(A, p, q, r);
}
}
template <typename T>
void MergeSortWithoutSoilder(T* A, int siz)//对包含siz个数的A数组归并排序,这里没有设置哨兵
{
MergeSortWithoutSoilder<T>(A, 0, siz - 1);
}
template <typename T>
void MergeWithoutSoilder(T* A, int p, int q, int r)//不可从外部调用的归并函数
{
int n1 = q - p + 1, n2 = r - q;
T *L = new T[n1], *R = new T[n2];
for (int i = 0; i < n1; i++) L[i] = A[p + i];
for (int i = 0; i < n2; i++) R[i] = A[q + i + 1];
int i = 0, j = 0, lnum = 0, rnum = 0;
for (int k = p; k <= r; k++)
{
if (i == n1 && j != n2)
{
while (j != n2) A[k++] = R[j++];
break;
}
if (i != n1 && j == n2)
{
while (i != n1) A[k++] = L[i++];
break;
}
if (L[i] < R[j]) A[k] = L[i++];
else A[k] = R[j++];
}
delete[] L, R;
}
void MergeSortTest(int num = 10000);
void MergeCompareTest(int num = 1000);
template <typename T>
void MergeSortImprove(T* A, int p, int r, int d)
//对递归的小于等于d个元素的数组使用插入排序
{
if (p < r)
{
int q = (p + r) / 2;
if (q - p + 1 <= d)
{
InsertionSort(A + p, q - p + 1);
InsertionSort(A + q + 1, r - q);
}
else
{
MergeSortImprove(A, p, q, d);
MergeSortImprove(A, q + 1, r, d);
Merge(A, p, q, r);
}
}
}
template <typename T>
void MergeSortImprove(T* A, int p, int r)
//对int类型,在未知d值时,这个函数会先测出d值
{
MergeSortImprove(A, p, r, MergeBetterInsertion<T>());
}
template <typename T>
void InsertionSort(T* A, int siz)//对有siz个元素的A数组插入排序
{
for (int i = 1; i < siz; i++)
{
int temp = A[i];
int j = i;
while (j > 0 && A[j - 1] > temp)
{
A[j] = A[j - 1];
j--;
}
A[j] = temp;
}
}
template <typename T>
void ChooseSort(T* A, int siz)
{
for (int i = 0; i < siz; i++)
{
int k = i;
for (int j = i + 1; j < siz; j++)
if (A[j] < A[k]) k = j;
int temp = A[i];
A[i] = A[k];
A[k] = temp;
}
}
template <typename T>
void BubbleSort(T* A, int siz)
{
for (int i = 0; i < siz - 1; i++)
for (int j = siz - 1; j > i; j--)
if (A[j] < A[j - 1])
{
int temp = A[j];
A[j] = A[j - 1];
A[j - 1] = temp;
}
}
void SortTest(int num = 50000);
int MergeBetterInsertion(int maxans = 10000);//requires T has method "T my::random<T>()"
}
//Sort.cpp
#include "Sort.h"
#include <iostream>
#include <fstream>
#include <random>
using namespace std;
int my::MergeBetterInsertion(int maxans)//requires T has method "T my::random<T>()"
{
int *a, *b;
for (int ans = 1000; ans <= maxans; ans += 100)
{
a = new int[ans];
b = new int[ans];
random_device rd;
for (int i = 0; i < ans; i++)
{
b[i] = a[i] = rd();
}
auto istart = system_clock::now();
InsertionSort<int>(a, ans);
auto idiff = system_clock::now() - istart;
auto mstart = system_clock::now();
MergeSort<int>(b, ans);
auto mdiff = system_clock::now() - mstart;
delete[] a, b;
if (mdiff < idiff) return ans;
}
return maxans;
}
void my::SortTest(int num)
{
random_device rd;
int *r1 = new int[num], *r2 = new int[num], *r3 = new int[num];
for (int i = 0; i < num; i++)
{
r1[i] = rd() % (num * 10);
r2[i] = r1[i];
r3[i] = r1[i];
}
cout << "Sort " << num << " data type int:" << endl;
auto start = system_clock::now();
InsertionSort<int>(r1, num);
auto diff = system_clock::now() - start;
cout << "InsertionSort: " << duration_cast<milliseconds>(diff).count() << " milliseconds." << endl;
start = system_clock::now();
ChooseSort<int>(r2, num);
diff = system_clock::now() - start;
cout << "ChooseSort: " << duration_cast<milliseconds>(diff).count() << " milliseconds." << endl;
start = system_clock::now();
BubbleSort<int>(r3, num);
diff = system_clock::now() - start;
cout << "BubbleSort: " << duration_cast<milliseconds>(diff).count() << " milliseconds." << endl;
/*
ofstream fout("out_Sort.txt");
fout << "InsertionSort:" << endl; for (int i = 0; i < num; i++) fout << r1[i] << "\t"; fout << endl;
fout << "ChooseSort:" << endl; for (int i = 0; i < num; i++) fout << r2[i] << "\t"; fout << endl;
fout << "BubbleSort:" << endl; for (int i = 0; i < num; i++) fout << r3[i] << "\t"; fout << endl;
fout.close();
*/
delete[] r1, r2, r3;
system("pause");
}
void my::MergeSortTest(int num)
{
int *randomnum = new int[num];
random_device rd;
for (int i = 0; i < num; i++) randomnum[i] = rd() % (num * 10);
ofstream fout("out_MergeSort.txt");
for (int i = 0; i < num; i++) fout << randomnum[i] << "\t";
auto start = chrono::system_clock::now();
MergeSort<int>(randomnum, num);
auto diff = chrono::system_clock::now() - start;
fout << endl << "Time used by MergeSort for " << num << " elements (type int) is "
<< chrono::duration_cast<chrono::nanoseconds>(diff).count() << " nanoseconds." << endl;
cout << "Time used by MergeSort for " << num << " elements (type int) is "
<< chrono::duration_cast<chrono::nanoseconds>(diff).count() << " nanoseconds." << endl;
for (int i = 0; i < num; i++) fout << randomnum[i] << "\t";
fout << endl;
fout.close();
delete[] randomnum;
system("pause");
}
void my::MergeCompareTest(int num)
{
int *ran1 = new int[num], *ran2 = new int[num];
random_device rd;
for (int i = 0; i < num; i++)
{
ran1[i] = rd() % (num * 10);
ran2[i] = ran1[i];
}
ofstream fout("out_MergeCompare.txt");
for (int i = 0; i < num; i++) fout << ran1[i] << "\t";
fout << endl;
auto start = chrono::system_clock::now();
MergeSort<int>(ran1, 0, num - 1);
auto diff = chrono::system_clock::now() - start;
fout << "Time used by MergeSort with soilder for " << num << " elements (type int) is "
<< chrono::duration_cast<chrono::nanoseconds>(diff).count() << " nanoseconds." << endl;
for (int i = 0; i < num; i++) fout << ran1[i] << "\t";
fout << endl;
start = chrono::system_clock::now();
MergeSortWithoutSoilder(ran2, 0, num - 1);
diff = chrono::system_clock::now() - start;
fout << "Time used by MergeSort without soilder for " << num << " elements (type int) is "
<< chrono::duration_cast<chrono::nanoseconds>(diff).count() << " nanoseconds." << endl;
for (int i = 0; i < num; i++) fout << ran2[i] << "\t";
fout << endl;
fout.close();
delete[] ran1, ran2;
cout << "To see all the information about comparation of the two merge sorts, find file \"out_MergeCompare.txt\"." << endl;
system("pause");
}
//main.cpp
#include "Sort.h"
using namespace my;
int main()
{
SortTest();
MergeSortTest();
MergeCompareTest();
return 0;
}
若出现头文件不存在的问题,请尝试更换为最新版VS2017并重定项目目标。如果发现有错误请及时与我联系,我会定期查看我的博客。