归并排序(二)

本文介绍了一种改进的归并排序算法,通过结合插入排序提升小规模数组排序效率,并对比了不同排序算法的时间性能。
这次仍然是归并排序,在此基础上做了一点点的改进:对小数量的数组用插入排序代替。所以在运行归并排序之前,要先生成小的数组来比较插入排序和归并排序,确定数组大小在小于多少的时候使用插入排序。由于不同机器存在差异,而且排序速度与原始数组也有关,因此我的预设值为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并重定项目目标。如果发现有错误请及时与我联系,我会定期查看我的博客。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值