九大經典排序算法整理及其源代碼分享(純C++版)

九大經典排序算法整理及其源代碼分享(純C++版)
[TOC]

頭文件–9sortEx.h

#ifndef SORTEX_H_
#define SORTEX_H_

typedef int Comparable;

#include <vector>
using std::vector;

class sortEx
{
public:
    //static bool lessThan(Comparable v, Comparable w);
    void exch(int i, int j);
    bool isSorted()const;
    void show()const;
    virtual void sort() = 0;
protected:
    sortEx(int n = 0);
    vector<Comparable> a;
};

class insertSortStraight :public sortEx
{
public:
    insertSortStraight(int n):sortEx(n){ }
    void sort();
};

class insertSortShell :public sortEx
{
public:
    insertSortShell(int n) :sortEx(n)
    {
    }
    void sort();
};

class swapSortBubble :public sortEx
{
public:
    swapSortBubble(int n) :sortEx(n)
    {
    }
    void sort();
};

class swapSortQuick :public sortEx
{
public:
    swapSortQuick(int n) :sortEx(n)
    {
    }
    void sort();
private:
    int Partition(int st, int ed);   //[st, ed]
    void sort(int st, int ed);       //[st, ed)
};


class selectionSortSimple :public sortEx
{
public:
    selectionSortSimple(int n) :sortEx(n)
    {
    }
    void sort();
};

class selectionSortHeap :public sortEx
{
public:
    selectionSortHeap(int n) :sortEx(n)
    {
    }
    void sort();
private:
    void createHeap();
    void heapAdjust(int totalN, int pos);
};

class mergeSort :public sortEx
{
public:
    mergeSort(int n) :sortEx(n)
    {
        aux.resize(n);
    }
    //自頂向下的歸併
    void sort();
    //自底向上的歸併
    void sortAnther();
private:
    void sort(int st, int ed);            //[st, ed]
    void merge(int st, int mid, int ed);  //[st, ed]
    vector<Comparable> aux;
    int minNum(int a, int b)
    {
        return a < b ? a : b;
    }
};

class countSort :public sortEx
{
public:
    countSort(int n) :sortEx(n)
    {
    }
    void sort();
};

class radixSort :public sortEx
{
public:
    radixSort(int n) :sortEx(n), RADIX(10)
    {
    }
    void sort();
private:
    int getRadix(int num, int sq);
    void Distribute(int sq, vector<int>& cnt);
    void Collect(int sq, vector<int>& cnt, vector<int>& tmp);
    const int RADIX;
};

#endif

類實現文件–9sortEx.cpp

/*
 * ---------------------------------------------------
 *  Copyright (c) 2017 josan All rights reserved.
 * ---------------------------------------------------
 *
 *               創建者: Josan
 *             創建時間: 2017/9/3 15:28:42
 */
#include <iostream>
#include <vector>
#include <cassert>
#include <iomanip>
#include <cmath>
#include <queue>
#include <functional>
#include <cassert>
#include "9sortEx.h"
using namespace std;

sortEx::sortEx(int n /* = 0 */)
{
    assert(0 <= n);
    a.resize(n);
    for(int i = 0; i < n; ++i)
    {
        cin >> a[i];
    }
}

void sortEx::exch(int i, int j)
{
    Comparable tmp;
    tmp = a[i];
    a[i] = a[j];
}

bool sortEx::isSorted()const
{
    int n = static_cast<int>(a.size());
    for(int i = 1; i < n; ++i)
    {
        if(a[i - 1] > a[i])
        {
            return false;
        }
    }
    return true;
}

void sortEx::show()const
{
    assert(isSorted());
    int n = static_cast<int>(a.size());
    int sz = 0;
    for(int i = 0; i < n; ++i)
    {
        cout << left << setw(4) << a[i];
        sz = (sz + 1) % 10;
        if(0 == sz)
        {
            cout << endl;
        }
    }
    cout << endl;
}

void insertSortStraight::sort()
{
    int n = static_cast<int>(a.size());
    for(int i = 1; i < n; ++i)
    {
        Comparable tem = a[i];
        int j = i;
        for(; 1 <= j&&tem < a[j - 1]; --j)
        {
            a[j] = a[j - 1];
        }
        a[j] = tem;
    }
}

void insertSortShell::sort()
{
    int n = static_cast<int>(a.size());
    for(int step = (n >> 1); 1 <= step; step >>= 1)
    {
        for(int st = 0; st < step; ++st)
        {
            for(int i = st + step; i < n; i += step)
            {
                Comparable tem = a[i];
                int j = i;
                for(; st + step <= j&&tem < a[j - step]; j -= step)
                {
                    a[j] = a[j - step];
                }
                a[j] = tem;
            }
        }
    }
}

void swapSortBubble::sort()
{
    int n = static_cast<int>(a.size());
    for(int i = 1; i < n; ++i)
    {
        for(int j = 0; j < n - i; ++j)
        {
            if(a[j + 1] < a[j])
            {
                exch(j, j+1);
            }
        }
    }
}

void swapSortQuick::sort()
{
    int n = static_cast<int>(a.size());
    sort(0, n);
}

void swapSortQuick::sort(int st, int ed)
{
    if(ed - st < 2)
    {
        return;
    }
    int pos = Partition(st, ed - 1);
    sort(st, pos);
    sort(pos + 1, ed);
}

int swapSortQuick::Partition(int st, int ed)
{
    Comparable tem = a[st];
    while(st < ed)
    {
        while(st < ed&&tem <= a[ed])
        {
            --ed;
        }
        a[st] = a[ed];
        while(st < ed&&a[st] <= tem)
        {
            ++st;
        }
        a[ed] = a[st];
    }
    a[st] = tem;
    return st;
}

void selectionSortSimple::sort()
{
    int n = static_cast<int>(a.size());
    for(int i = 0; i < n - 1; ++i)
    {
        int minIdx = i;
        for(int j = i + 1; j < n; ++j)
        {
            if(a[j] < a[minIdx])
            {
                minIdx = j;
            }
        }
        if(minIdx != i)
        {
            exch(i, minIdx);
        }
    }
}

//使用標準庫的優先隊列,進行堆排序
void selectionSortHeap::sort()
{
    int n = static_cast<int>(a.size());
    priority_queue<int, vector<int>, greater<int>> Q;   //小頂堆
    //默認是大頂堆
    // priority_queue<int, vector<int>, less<int>> Q;    //使用priority_queue<int> Q;一樣
    for(auto x : a)
    {
        Q.push(x);
    }
    int i = 0;
    while(!Q.empty())
    {
        a[i++] = Q.top();
        Q.pop();
    }
}

//void selectionSortHeap::sort()
//{
//  int n = static_cast<int>(a.size());
//  createHeap();
//  for(int i = n - 1; 0 < i; --i)
//  {
//      exch(i, 0);
//      heapAdjust(i, 0);
//  }
//}
//
//void selectionSortHeap::createHeap()
//{
//  int n = static_cast<int>(a.size());
//  for(int i = (n - 1) / 2; 0 <= i; --i)
//  {
//      heapAdjust(n, i);
//  }
//}
//
//void selectionSortHeap::heapAdjust(int totalN, int pos)
//{
//  int n = static_cast<int>(a.size());
//  Comparable tem = a[pos];
//  int i = pos;
//  for(int j = pos * 2 + 1; j < n; j = j * 2 + 1)
//  {
//      if(j + 1 < n&&a[j] < a[j + 1])
//      {
//          ++j;
//      }
//      if(tem >= a[j])
//      {
//          break;
//      }
//      else
//      {
//          a[i] = a[j];
//          i = j;
//      }
//  }
//  a[i] = tem;
//}

void mergeSort::sort()
{
    int n = static_cast<int>(a.size());
    sort(0, n - 1);
}

void mergeSort::sort(int st, int ed)
{
    if(st < ed)
    {
        int mid = st + (ed - st) / 2;
        sort(st, mid);
        sort(mid + 1, ed);
        merge(st, mid, ed);
    }
}

void mergeSort::merge(int st, int mid, int ed)
{
    int i = st;
    int j = mid + 1;
    for(int k = st; k <= ed; ++k)
    {
        aux[k] = a[k];
    }

    for(int k = st; k <= ed; ++k)
    {
        if(i > mid)
        {
            a[k] = aux[j++];
        }
        else if(j > ed)
        {
            a[k] = aux[i++];
        }
        else if(aux[j] < aux[i])
        {
            a[k] = aux[j++];
        }
        else
        {
            a[k] = aux[i++];
        }
    }
}

void mergeSort::sortAnther()
{
    int n = static_cast<int>(a.size());
    for(int sz = 1; sz < n; sz <<= 1)
    {
        for(int st = 0; st < n - sz; st += sz * 2)
        {
            merge(st, st + sz + 1, minNum(st + sz + sz - 1, n - 1));
        }
    }
}
void countSort::sort()
{
    //假設數組元素在0~499之間
    vector<int> cntAux(500, 0);
    int n = static_cast<int>(a.size());
    for(int i = 0; i < n; ++i)
    {
        ++cntAux[a[i]];
    }
    for(int i = 1; i < 500; ++i)
    {
        cntAux[i] += cntAux[i - 1];
    }

    vector<Comparable> tmp(a);
    for(int i = n - 1; 0 <= i; --i)
    {
        a[--cntAux[tmp[i]]] = tmp[i];
    }
}

void radixSort::sort()
{
    int n = static_cast<int>(a.size());
    int d = 3;
    vector<int> cnt(RADIX);
    vector<Comparable> tmp(n);

    for(int i = 0; i < d; ++i)
    {
        //分配
        Distribute(i, cnt);
        //收集
        Collect(i, cnt, tmp);
    }
}

int radixSort::getRadix(int num, int sq)
{
    return (num / static_cast<int>(pow(RADIX, sq))) % RADIX;
}

void radixSort::Distribute(int sq, vector<int>& cnt)
{
    //初始化
    int n = static_cast<int>(a.size());
    for(auto& x : cnt)
    {
        x = 0;
    }
    for(int i = 0; i < n; ++i)
    {
        int ord = getRadix(a[i], sq);
        ++cnt[ord];
    }
}

void radixSort::Collect(int sq, vector<int>& cnt, vector<int>& tmp)
{
    int n = static_cast<int>(a.size());
    for(int i = 1; i < RADIX; ++i)
    {
        cnt[i] += cnt[i - 1];
    }
    for(int i = 0; i < n; ++i)
    {
        tmp[i] = a[i];
    }
    for(int i = n - 1; 0 <= i; --i)
    {
        int ord = getRadix(tmp[i], sq);
        a[--cnt[ord]] = tmp[i];
    }
}

測試程序–test.cpp

/*
 * ---------------------------------------------------
 *  Copyright (c) 2017 josan All rights reserved.
 * ---------------------------------------------------
 *
 *               創建者: Josan
 *             創建時間: 2017/9/3 16:50:31
 */
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <fstream>
#include <ctime>
#include "9sortEx.h"
using namespace std;

#define INPUTTEST 0
#define OUTPUTTEST 0
template <typename T>
static void testSort(const string& sortName)
{
    ifstream fin("tinyUnsortedNum.txt");
    //cinbk作爲cin對象的讀取緩衝區的臨時存儲對象
    streambuf* cinbk;
    //[old]streambuf* rdbuf(streambuf* newbf);  
    //調用這個方法可以設置新的讀取緩衝區,返回舊的緩衝區 
    cinbk = cin.rdbuf(fin.rdbuf());
    string str(sortName);
    str += "tinySortedNum.txt";
    ofstream fout(str);
    //coutbk作爲cout對象的寫入緩衝區的臨時存儲對象
    streambuf* coutbk;
    coutbk = cout.rdbuf(fout.rdbuf());
    //--------------- start of test --------------
    clock_t t_st, t_ed;
    t_st = clock();
    int n;
    cin >> n;
    T sTiny(n);
    sTiny.sort();
    sTiny.show();
    t_ed = clock();
    cout << "The time of sort is " << t_ed - t_st << " ms." << endl;

    fin.close();
    fin.open("mediumUnsortedNum.txt");
    fout.close();
    str = sortName;
    str += "mediumSortedNum.txt";
    fout.open(str);
    t_st = clock();
    cin >> n;
    T sMedium(n);
    sMedium.sort();
    sMedium.show();
    t_ed = clock();
    cout << "The time of sort is " << t_ed - t_st << " ms." << endl;

    fin.close();
    fin.open("largeUnsortedNum.txt");
    fout.close();
    str = sortName;
    str += "largeSortedNum.txt";
    fout.open(str);
    t_st = clock();
    cin >> n;
    T sLarge(n);
    sLarge.sort();
    sLarge.show();
    t_ed = clock();
    cout << "The time of sort is " << t_ed - t_st << " ms." << endl;
    //--------------- end   of test --------------
    fout.close();
    cout.rdbuf(coutbk);
    fin.close();
    cin.rdbuf(cinbk);
}

static void test()
{
    testSort<insertSortStraight>("insertSortStraight");
    testSort<insertSortShell>("insertSortShell");
    testSort<swapSortBubble>("swapSortBubble");
    testSort<swapSortQuick>("swapSortQuick");
    testSort<selectionSortSimple>("selectionSortSimple");
    testSort<selectionSortHeap>("selectionSortHeap");
    testSort<mergeSort>("mergeSort");
    testSort<countSort>("countSort");
    testSort<radixSort>("radixSort");
}

int main(int argc, char* argv[])
{
#if INPUTTEST
    ifstream fin("tinyUnsortedNum.txt");
    //cinbk作爲cin對象的讀取緩衝區的臨時存儲對象
    streambuf* cinbk;
    //[old]streambuf* rdbuf(streambuf* newbf);  
    //調用這個方法可以設置新的讀取緩衝區,返回舊的緩衝區 
    cinbk = cin.rdbuf(fin.rdbuf());
#endif
#if OUTPUTTEST
    ofstream fout("out.txt");
    //coutbk作爲cout對象的寫入緩衝區的臨時存儲對象
    streambuf* coutbk;
    coutbk = cout.rdbuf(fout.rdbuf());
#endif
    //--------------- start of main --------------
    test();
    //--------------- end   of main --------------
#if OUTPUTTEST
    fout.close();
    cout.rdbuf(coutbk);
#endif
#if INPUTTEST
    fin.close();
    cin.rdbuf(cinbk);
#endif  
    return 0;
}

測試文件和測試環境說明

  • 測試文件
    所有的測試文件都是隨機產生。其中,數值的範圍在[0, 500)之間。

tinyUnsortedNum.txt 數據規模爲10

mediumUnsortedNum.txt 數據規模爲200

largeUnsortedNum.txt 數據規模爲10000

  • 測試環境
    IDE環境: Visual Studio 2015 Enterprise (Debug模式下)
    處理器: AMD A8-7650K Radeon R7, 10 Compute Cores 4C+6G 3.30GHz

測試結果

直接插入排序:
The time of sort is 0 ms.
The time of sort is 17 ms.
The time of sort is 38240 ms.

希爾排序:
The time of sort is 0 ms.
The time of sort is 5 ms.
The time of sort is 426 ms.

冒泡排序:
The time of sort is 0 ms.
The time of sort is 23 ms.
The time of sort is 51979 ms.

快速排序:
The time of sort is 1 ms.
The time of sort is 3 ms.
The time of sort is 271 ms.

簡單選擇排序:
The time of sort is 0 ms.
The time of sort is 21 ms.
The time of sort is 51855 ms.

堆排序:
The time of sort is 1 ms.
The time of sort is 7 ms.
The time of sort is 4450 ms.

歸併排序:
The time of sort is 0 ms.
The time of sort is 7 ms.
The time of sort is 490 ms.

計數排序:
The time of sort is 1 ms.
The time of sort is 2 ms.
The time of sort is 108 ms.

基數排序:
The time of sort is 1 ms.
The time of sort is 4 ms.
The time of sort is 212 ms.

結果分析

都說快速排序是O(nlgn)中最好的,直接插入排序是O(n^2)中最好的。現在可以直接看到實驗結果確實是這樣的。(多次隨機後,仍然得出此結論。)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章