O(n^2)排序及O(nlog(n))排序

main.cpp

#include 
#include "SortTestHelper.h"
#include "SortAlgorithm.h"

int main() {
    /* 100万个数据的排序结果

    对一个随机数组进行排序
    Shell Sort: :51.5798s
    Merge Sort: :0.231673s
    QuickSort Sort: :0.255111s
    2 Ways Quick Sort: :0.181188s
    3 Ways Quick Sort: :0.303083s

    对近乎有序的数组进行排序
    Shell Sort: :0.122397s
    Merge Sort: :0.065564s
    QuickSort Sort: :0.179152s
    2 Ways Quick Sort: :0.069877s
    3 Ways Quick Sort: :0.229419s

    对存在大量重复元素的数组进行排序
    Shell Sort: :51.1946s
    Merge Sort: :0.179235s
    QuickSort Sort: :11.8389s
    2 Ways Quick Sort: :0.121224s
    3 Ways Quick Sort: :0.086746s*/

    int n = 1000000;
    cout<<"对一个随机数组进行排序"<

SortTestHelper.h

#ifndef SELECTIONSORT_SORTTESTHELPER_H
#define SELECTIONSORT_SORTTESTHELPER_H

#include 
#include 
#include 
using namespace std;

namespace SortTestHelper{

    //返回一个在[rangeL,rangeR]范围内元素数量为n的随机整形数组
    int* generateRandomArray(int n, int rangeL, int rangeR){

        assert(rangeL < rangeR);
        int* arr = new int[n];
        srand(time(NULL)); //设置随机种子
        for (int i = 0; i < n; ++i) {
           arr[i] = rand() % (rangeR - rangeL + 1) + rangeL;
        }
        return arr;
    }

    template 
    void printArray(T arr ,int n){
        for(int i = 0; i < n; i++){
            cout << arr[i] << " ";
        }
        cout << endl;
    }

    template 
    bool isSorted(T arr, int n, const string sortName){
        for (int i = 0; i < n - 1; ++i) {
            if(arr[i]>arr[i+1]){
                cout << "sort failed: " << sortName << ".";
                return false;
            }
        }
        return true;
    }

    template 
    void testSort(const string &sortName, void(*sort)(T[], int n), T arr[], int n){
        clock_t startTime = clock();
        sort(arr,n);
        clock_t endTime = clock();

        assert(isSorted(arr,n,sortName));

        cout << sortName << ":" <<(float)(endTime-startTime)/CLOCKS_PER_SEC << "s" <
    int getArrLength(T& arr){
        //T& arr是对变量的引用,而不是取地址(取地址是& arr,没有前面的类型声明)。
        //通过T& arr引用变量实际上是给实参变量取了一个叫做arr的别名。在内部使用arr就是对实参变量的操作。
        //这是C++对C的一个补充用法。
        return sizeof(arr)/ sizeof(arr[0]);

    }


}
#endif //SELECTIONSORT_SORTTESTHELPER_H

SortAlgorithm.h

#ifndef INSERTSORT_SELECTIONSORT_H
#define INSERTSORT_SELECTIONSORT_H

using namespace std;
namespace On2 {
    template
    // 选择排序
    void selectionSort(T arr[], int n) {
        for (int i = 0; i < n; i++) {
            int minIndex = i;
            for (int j = minIndex; j < n; j++) {
                if (arr[j] < arr[minIndex])
                    minIndex = j;
            }
            swap(arr[i], arr[minIndex]);
        }
    }

    template
    // 插入排序
    void insertSortV1(T arr[], int n) {
        for (int i = 1; i < n; ++i) {
            /*for (int cur = i; cur >0 ; --cur) {
                if(arr[cur] 0 && arr[cur] < arr[cur - 1]; cur--) {
                swap(arr[cur], arr[cur - 1]);
            }
        }
    }


    template
    // 优化后的插入排序,通过以赋值替换swap、提前终止遍历的方式,提高排序速度
    void insertSortV2(T arr[], int n) {
        for (int i = 1; i < n; ++i) {
            int min = arr[i];
            int j = i;
            for (; j > 0 && arr[j - 1] > min; j--) {
                arr[j] = arr[j - 1];
            }
            arr[j] = min;
        }
    }

    template
    // 插入排序。在其他O(nlogn)算法递归到数据量较少时,改用插入排序提高运行速率
    void insertSort(T arr[], int left, int right) {
        for (int i = left + 1; i <= right; ++i) {
            int min = arr[i];
            int j = i;
            for (; j > left && arr[j - 1] > min; j--) {
                arr[j] = arr[j - 1];
            }
            arr[j] = min;
        }
    }

    template
    //冒泡排序
    void bubbleSort(T arr[], int n) {
        // 每一轮依次对数组arr[0,i]的j和j+1位置进行比大小,若arr[j]>arr[j+1]则将arr[j]沉底
        for (int i = n - 1; i > 0; i--) {
            for (int j = 0; j < i; ++j) {
                if (arr[j] > arr[j + 1]) {
                    swap(arr[j], arr[j + 1]);
                }
            }
        }

    }

    template
    // 希尔排序的增量序列可选择Hibbard增量,即2^k-1,也可以选择质数序列。
    void shellSort(T arr[], int n) {
        // 对大小为n的数组执行希尔排序,处理的步长序列为[3,2,1]
        int step[] = {31, 29, 23, 19, 17, 13, 11, 9, 7, 5, 3, 2, 1};
        int stepLenth = sizeof(step) / sizeof(step[0]);
        for (int i = 0; i < stepLenth; i++) {
            // 对数组arr以步长step[i]切分子数组,在这些子数组上执行插入排序
            int initPos = 0;
            while (initPos < step[i]) {
                // 对子数组arr[initPos,initPos+step[i],initPos+2*step[i]...initPos+k*step]执行插入排序,其中initPos+k*step initPos; y -= step[i]) {
                        if (tmp < arr[y - step[i]])
                            arr[y] = arr[y - step[i]];
                        else
                            break;
                    }
                    arr[y] = tmp;
                }

                initPos++;
            }

        }
    }

}

namespace Onlogn {
    namespace QuickSortV1_1 {
        // 未进行任何优化的快速排序算法
        // 整理数组arr[left,right],使得所有位于[left,p-1]的元素都小于v,所有位于[p+1,right]的元素都大于v,
        // 其中v是arr[left,right]数组的第一个元素
        template
        int __partition(T arr[], int left, int right) {
            int v = arr[left];
            int p = left;
            for (int i = p + 1; i <= right; i++) {
                if (arr[i] < v) {
                    swap(arr[p + 1], arr[i]);
                    p += 1;
                }
            }
            swap(arr[left], arr[p]);
            return p;
        }

        // 对arr[left,right]进行快速排序
        template
        void __quickSort(T arr[], int left, int right) {
            if (left >= right)
                return;
            int p = __partition(arr, left, right);
            __quickSort(arr, left, p - 1);
            __quickSort(arr, p + 1, right);
        }

        template
        void quickSort(T arr[], int n) {
            __quickSort(arr, 0, n - 1);
        }
    }


    namespace QuickSortV1_2 {
        // 优化后的快速排序
        // 将arr[l...r]进行partition操作
        // 返回pivot元素索引p,使得arr[l...p-1] < arr[p], 且arr[p+1...r] > arr[p]
        template
        int __partition(T arr[], int l, int r) {
            // 将分为以下几个部分。
            // pivot点arr[l],arr[l+1....j]等小于pivot的元素,arr[j+1...i)等大于pivot的元素
            // 以及正在遍历的元素arr[i],尚未遍历的部分arr[i+1...r]

            // 优化2.不再使用最左边的元素作为标定点,而是在数组中任选一个元素当做标定点,从而避免快排partition不均衡退化为O(n^2)算法
            srand(static_cast(time(NULL)));
            swap(arr[l], arr[rand() % (r - l + 1) + l]);
            T v = arr[l];
            int j = l;
            for (int i = l + 1; i <= r; i++) {
                // 初始时,v为第一个元素arr[l],正在遍历的元素为i
                // 小于元素v的区间[l+1...j]不存在,因为初始时j=l,l+1>j,区间变成了[l+1,l]。
                // 大于元素v的区间[j+1...i)不存在,因为初始时i=l+1,而l=j,区间变成了[j+1,j+1)。
                if (arr[i] < v) {
                    swap(arr[j + 1], arr[i]);
                    j++;
                }
            }
            swap(arr[l], arr[j]);
            return j;
        }

        // 对arr[left...right]进行快速排序
        template
        void __quickSort(T arr[], int left, int right) {
            // 优化1.当剩余需要排序的数组元素数量低于一定数量时,使用插入排序进行处理
            if (right - left <= 10) {
                On2::insertSort(arr, left, right);
                return;
            }

            int p = __partition(arr, left, right);
            __quickSort(arr, left, p - 1);
            __quickSort(arr, p + 1, right);
        }

        template
        void quickSort(T arr[], int n) {
            __quickSort(arr, 0, n - 1);
        }
    }
    namespace QuickSort2ways{
        // 双路快排
        // 对arr[l...r]进行双路partition操作,
        // 其中v表示pivot标定点元素,arr[i]表示当前遍历的元素,arr[j]为当前未遍历的最后一个元素
        // 通过partition整理数组,使得arr[l+1...i)<=arr[l],arr(j...r]>=arr[l]。
        // 若存在大量重复元素,由于i定义为第一个大于等于v的位置,j定义为第一个小于等于v的位置
        // partition后的效果为(ev),由于存在swap操作,因此partition后这些重复的元素会分别放在p的左右两侧
        // 这就避免了左右子区间元素数量出现倾斜,导致退化为O(n^2)的情况

        template 
        int __partition(T arr[], int l, int r){

            swap(arr[l], arr[(rand()%(r-l+1))+l]);

            T v = arr[l];
            int i = l+1;
            int j = r;
            while(true){
                //i: 遍历时第一个使得arr[i]>=v的索引
                while (arr[i] < v && i<=r){
                    i++;
                }
                //j: 遍历时第一个使得arr[j]<=v的索引
                while (arr[j] > v && j>l){
                    j--;
                }
                if (i>j) break;
                swap(arr[i], arr[j]);
                i++;
                j--;
            }
            swap(arr[l] , arr[j]);
            return j;
        }


        // 对arr[l...r]进行双路快速排序
        template 
        void __quickSort(T arr[], int l, int r){
            if(r-l<=15){
                On2::insertSort(arr, l, r);
                return;
            }

            int p = __partition(arr, l, r);
            __quickSort(arr, l, p-1);
            __quickSort(arr, p+1, r);
        }

        // 对arr[0...n-1]进行双路快速排序
        template 
        void quickSort2Ways(T arr[], int n){
            srand(time(NULL));
            __quickSort(arr, 0, n-1);
        }
    }

    namespace QuickSort3Ways{
        //三路快排
        // 对arr数据进行三路快排操作
        // 使得arr[l+1...lt]v
        // 其中lt表示当前循环中的最后一个小于v的元素的索引,gt表示第一个大于v的索引,
        // arr[i...gt-1]为尚未处理的元素,i为当前将要遍历的元素索引
        template 
        void __quickSort(T arr[], int l, int r){
            if (r-l <= 10){
                On2::insertSort(arr, l, r);
                return;
            }

            // partition部分
            swap(arr[l], arr[rand()%(r-l+1) + l]);
            T v = arr[l];

            int lt = l;
            int gt = r+1;
            int i = l+1;

            while (i < gt){
                if(arr[i] < v){
                    swap(arr[i], arr[lt+1]);
                    i++;
                    lt++;
                }
                else if(arr[i] > v){
                    swap(arr[i], arr[gt-1]);
                    gt--;
                }
                else{ // arr[i] == v
                    i++;
                }
            }
            swap(arr[l], arr[lt]);
            lt -= 1; // 用于维护lt的定义:lt表示最后一个小于v的元素的索引

            // 递归处理
            __quickSort(arr, l, lt);
            __quickSort(arr, gt, r);
        }

        template 
        void quickSort3Ways(T arr[], int n){
            srand(time(NULL));
            __quickSort(arr, 0, n-1);
        }
    }
    namespace MergeSort {
        // 归并排序

        template
        void __merge(T &arr, int left, int right) {
            // copy array
            int size = right - left + 1;
            int copyArr[size];
            for (int i = 0; i < size; i++) {
                copyArr[i] = arr[i + left];
            }

            // cur - 当前需要排序的位置
            // posI、posJ - 复制的数组中需要判断大小的位置
            int cur = left;
            int posI = 0;
            int posJ = (size - 1) / 2 + 1;
            while (cur <= right) {
                if ((copyArr[posJ] < copyArr[posI] && posJ < size) or (posI > (size - 1) / 2)) {
                    arr[cur] = copyArr[posJ];
                    posJ++;
                } else {
                    arr[cur] = copyArr[posI];
                    posI++;
                }
                cur++;
            }


        }

        template
        void __mergeSort(T arr[], int left, int right) {
//             if (left == right)
//             return;
            if (right - left <= 8) { // 当剩余元素个数低于某个值时使用插入排序进行排序
                On2::insertSort(arr, left, right);
                return;
            }
            int mid = (right - left) / 2 + left;
            __mergeSort(arr, left, mid);
            __mergeSort(arr, mid + 1, right);
            if (arr[mid] > arr[mid + 1])
                __merge(arr, left, right);
        }

        template
        void mergeSort(T arr[], int n) {
            __mergeSort(arr, 0, n - 1);

        }
    }

    namespace MergeSortBU {
        // MergeSortBotomToUp
        // 自底向上的归并排序,不再进行递归处理将数据分为一个个小区间
        // 而是将数据直接视作最底层,向上归并。
        template
        void __merge(T arr[], int left, int mid, int right) {
            int size = right - left + 1;
            T arrCopy[size];
            for (int i = left; i <= right; i++) {
                arrCopy[i - left] = arr[i];
            }
            // 对arr[left,mid]和arr[mid+1,right]进行merge操作
            int l = 0;
            int r = mid - left + 1;
            for (int i = left; i <= right; ++i) {
                if (l > mid) {
                    arr[i] = arrCopy[r];
                    r++;
                } else if (r > size - 1) {
                    arr[i] = arrCopy[l];
                    l++;
                } else if (arrCopy[l] > arrCopy[r]) {
                    arr[i] = arrCopy[r];
                    r++;
                } else {
                    arr[i] = arrCopy[l];
                    l++;
                }
            }
        }

        template
        void mergeSortBU(T arr[], int n) {
            // 对arr[i,i+sz-1]和arr[i+sz,i+2*zs-1]进行merge
            // i+sz

你可能感兴趣的:(O(n^2)排序及O(nlog(n))排序)