• 排序算法总结-选择排序、插入排序、归并排序和快速排序


      前言:

      感觉好久没写博客了,十月份的计划是:要开始深入攻克数据结构和算法,耽误好久了,这都月末了,抓紧时间又学习了一波,赶紧来分享了一下,使用的语言是C++,最开始学数据结构一定要用C,掌握扎实之后,想学算法,用C++比较好,C封装没有那么好,写起来没有那么容易了。

      一、准备工作

      这部分会封装一些接口,如生成数组、测试排序算法执行时间等,便于比较和调试。封装在.h中,如下:

      

    #ifndef SORTTESTHELPER_H_
    #define SORTTESTHELPER_H_
    
    #include <iostream>
    #include <ctime>
    #include <cassert>
    #include <string>
    
    using namespace std;
    
    namespace SortTestHelper {
    
        // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR]
        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;
        }
        //生成很相近的数组
        int *generateNearlyOrderedArray(int n, int swapTimes) {
    
            int *arr = new int[n];
            for (int i = 0; i < n; i++)
                arr[i] = i;
    
            srand(time(NULL));
            for (int i = 0; i < swapTimes; i++) {
                int posx = rand() % n;
                int posy = rand() % n;
                swap(arr[posx], arr[posy]);
            }
    
            return arr;
        }
        //copy一个数组
        int *copyIntArray(int a[], int n) {
    
            int *arr = new int[n];
            copy(a, a + n, arr);
            return arr;
        }
    
        //打印数组
        template<typename T>
        void printArray(T arr[], int n) {
    
            for (int i = 0; i < n; i++)
                cout << arr[i] << " ";
            cout << endl;
    
            return;
        }
        //是否已排好序
        template<typename T>
        bool isSorted(T arr[], int n) {
    
            for (int i = 0; i < n - 1; i++)
                if (arr[i] > arr[i + 1])
                    return false;
    
            return true;
        }
        //测试算法时间
        template<typename T>
        void testSort(const string &sortName, void(*sort)(T[], int), T arr[], int n) {
    
            clock_t startTime = clock();
            sort(arr, n);
            clock_t endTime = clock();
    
            assert(isSorted(arr, n));
            cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl;
    
            return;
        }
    
    };
    #endif //SORTTESTHELPER_H_
    View Code

      二、选择排序

      选择相对简单,就是两次循环,假如排序:从小到大,每次循环把小的移到前面,程序如下:

    #include <iostream>
    #include "test.h"
    
    using namespace std;
    
    //选择排序
    template<typename T>
    void selectionSort(T arr[], int n) {
    
        for (int i = 0; i < n; i++) {
    
            int minIndex = i;
            for (int j = i + 1; j < n; j++)
                if (arr[j] < arr[minIndex])
                    minIndex = j;
    
            swap(arr[i], arr[minIndex]);
        }
    }
    
    int main() {
    
        int n = 10000;
        int *arr = SortTestHelper::generateRandomArray(n, 0, n);
        SortTestHelper::testSort("Selection Sort", selectionSort, arr, n);
        delete[] arr;
    
        system("pause");
    
        return 0;
    }

      三、插入排序

      就是将较小的数据插入到前面,程序如下:

      

    #include <iostream>
    #include <algorithm>
    //#include "SortTestHelper.h"
    //#include "SelectionSort.h"
    #include"test.h"
    
    using namespace std;
    
    template<typename T>
    void insertionSort(T arr[], int n){
    
        for( int i = 1 ; i < n ; i ++ ) {
    
            // 寻找元素arr[i]合适的插入位置
            // 写法1
    //        for( int j = i ; j > 0 ; j-- )
    //            if( arr[j] < arr[j-1] )
    //                swap( arr[j] , arr[j-1] );
    //            else
    //                break;
    
            // 写法2
    //        for( int j = i ; j > 0 && arr[j] < arr[j-1] ; j -- )
    //            swap( arr[j] , arr[j-1] );
    
            // 写法3
            T e = arr[i];
            int j; // j保存元素e应该插入的位置
            for (j = i; j > 0 && arr[j-1] > e; j--)
                arr[j] = arr[j-1];
            arr[j] = e;
        }
    
        return;
    }
    
    int main() {
    
        int n = 10000;
        
        // 测试1 一般测试
        cout<<"Test for Random Array, size = "<<n<<", random range [0, "<<n<<"]"<<endl;
        int *arr1 = SortTestHelper::generateRandomArray(n,0,n);
        int *arr2 = SortTestHelper::copyIntArray(arr1, n);
    
        SortTestHelper::testSort("Insertion Sort", insertionSort,arr1,n);
        //SortTestHelper::testSort("Selection Sort", selectionSort,arr2,n);
    
        delete[] arr1;
        delete[] arr2;
    
        cout<<endl;
    
    
        // 测试2 有序性更强的测试
        cout<<"Test for More Ordered Random Array, size = "<<n<<", random range [0, 3]"<<endl;
        arr1 = SortTestHelper::generateRandomArray(n,0,3);
        arr2 = SortTestHelper::copyIntArray(arr1, n);
    
        SortTestHelper::testSort("Insertion Sort", insertionSort,arr1,n);
        //SortTestHelper::testSort("Selection Sort", selectionSort,arr2,n);
    
        delete[] arr1;
        delete[] arr2;
    
        cout<<endl;
    
    
        // 测试3 测试近乎有序的数组
        int swapTimes = 100;
        cout<<"Test for Random Nearly Ordered Array, size = "<<n<<", swap time = "<<swapTimes<<endl;
        arr1 = SortTestHelper::generateNearlyOrderedArray(n,swapTimes);
        arr2 = SortTestHelper::copyIntArray(arr1, n);
    
        SortTestHelper::testSort("Insertion Sort", insertionSort,arr1,n);
        //SortTestHelper::testSort("Selection Sort", selectionSort,arr2,n);
    
        delete(arr1);
        delete(arr2);
    
        system("pause");
    
        return 0;
    }
    View Code

      四、归并排序

      归并排序就比较复杂了,时间复杂度也从前两种的O(n^2)变为O(nlogn),代码如下:

      MergeSort.h如下:

      

    #ifndef INC_03_MERGE_SORT_ADVANCE_MERGESORT_H
    #define INC_03_MERGE_SORT_ADVANCE_MERGESORT_H
    
    #include <iostream>
    
    using namespace std;
    
    
    // 将arr[l...mid]和arr[mid+1...r]两部分进行归并
    template<typename  T>
    void __merge(T arr[], int l, int mid, int r) {
    
        // 经测试,传递aux数组的性能效果并不好
        T aux[r - l + 1];
        for (int i = l; i <= r; i++)
            aux[i - l] = arr[i];
    
        int i = l, j = mid + 1;
        for (int k = l; k <= r; k++) {
    
            if (i > mid) { arr[k] = aux[j - l]; j++; }
            else if (j > r) { arr[k] = aux[i - l]; i++; }
            else if (aux[i - l] < aux[j - l]) { arr[k] = aux[i - l]; i++; }
            else { arr[k] = aux[j - l]; j++; }
        }
    }
    
    // 递归使用归并排序,对arr[l...r]的范围进行排序
    template<typename T>
    void __mergeSort(T arr[], int l, int r) {
    
        if (l >= r)
            return;
    
        int mid = (l + r) / 2;
        __mergeSort(arr, l, mid);
        __mergeSort(arr, mid + 1, r);
        __merge(arr, l, mid, r);
    }
    
    template<typename T>
    void mergeSort(T arr[], int n) {
    
        __mergeSort(arr, 0, n - 1);
    }
    
    #endif //INC_03_MERGE_SORT_ADVANCE_MERGESORT_H
    View Code

      merge.cpp如下:

      

    #include <iostream>
    #include "test.h"
    //#include "InsertionSort.h"
    #include "MergeSort.h"
    
    using namespace std;
    
    
    // 递归使用归并排序,对arr[l...r]的范围进行排序
    template<typename T>
    void __mergeSort2(T arr[], int l, int r) {
    
        // 对于小规模数组,使用插入排序
        if (r - l <= 15) {
            insertionSort(arr, l, r);
            return;
        }
    
        int mid = (l + r) / 2;
        __mergeSort2(arr, l, mid);
        __mergeSort2(arr, mid + 1, r);
        // 对于arr[mid] <= arr[mid+1]的情况,不进行merge
        // 对于近乎有序的数组非常有效,但是对于一般情况,有一定的性能损失
        if (arr[mid] > arr[mid + 1])
            __merge(arr, l, mid, r);
    }
    
    template<typename T>
    void mergeSort2(T arr[], int n) {
    
        __mergeSort2(arr, 0, n - 1);
    }
    
    
    int main() {
    
        int n = 50000;
    
        // 测试1 一般性测试
        cout << "Test for Random Array, size = " << n << ", random range [0, " << n << "]" << endl;
        int* arr1 = SortTestHelper::generateRandomArray(n, 0, n);
        int* arr2 = SortTestHelper::copyIntArray(arr1, n);
        int* arr3 = SortTestHelper::copyIntArray(arr1, n);
    
        //SortTestHelper::testSort("Insertion Sort", insertionSort, arr1, n);
        SortTestHelper::testSort("Merge Sort", mergeSort, arr2, n);
        SortTestHelper::testSort("Merge Sort 2", mergeSort2, arr3, n);
    
        delete[] arr1;
        delete[] arr2;
        delete[] arr3;
    
        cout << endl;
    
    
        // 测试2 测试近乎有序的数组
        int swapTimes = 10;
        cout << "Test for Random Nearly Ordered Array, size = " << n << ", swap time = " << swapTimes << endl;
        arr1 = SortTestHelper::generateNearlyOrderedArray(n, swapTimes);
        arr2 = SortTestHelper::copyIntArray(arr1, n);
        arr3 = SortTestHelper::copyIntArray(arr1, n);
    
        //SortTestHelper::testSort("Insertion Sort", insertionSort, arr1, n);
        SortTestHelper::testSort("Merge Sort", mergeSort, arr2, n);
        SortTestHelper::testSort("Merge Sort 2", mergeSort2, arr3, n);
    
        delete[] arr1;
        delete[] arr2;
        delete[] arr3;
    
        return 0;
    }
    View Code

      五、快速排序

      

    template <typename T>
    int _partition2(T arr[], int l, int r){
    
        swap( arr[l] , arr[rand()%(r-l+1)+l] );
        T v = arr[l];
    
        // arr[l+1...i) <= v; arr(j...r] >= v
        int i = l+1, j = r;
        while( true ){
            while( i <= r && arr[i] < v )
                i ++;
    
            while( j >= l+1 && arr[j] > v )
                j --;
    
            if( i > j )
                break;
    
            swap( arr[i] , arr[j] );
            i ++;
            j --;
        }
    
        swap( arr[l] , arr[j]);
    
        return j;
    }
    
    template <typename T>
    void _quickSort(T arr[], int l, int r){
    
    //    if( l >= r )
    //        return;
        if( r - l <= 15 ){
            insertionSort(arr,l,r);
            return;
        }
    
        int p = _partition2(arr, l, r);
        _quickSort(arr, l, p-1 );
        _quickSort(arr, p+1, r);
    }
    
    template <typename T>
    void quickSort(T arr[], int n){
    
        srand(time(NULL));
        _quickSort(arr, 0, n-1);
    }
    View Code

      总结:

      数据结构和算法是基本功,必须深入学习,也是大厂总考的原因

      

      

      

  • 相关阅读:
    Lambda表达式
    java中解决小数精度问题
    [Unity]-黑魂复刻-动画 001
    kuka Virtual Remote pendant 连接使用
    C# 操作 pg 数据库
    C#常用字符串操作
    Go学习笔记之相关资源
    Go学习笔记之常用命令
    Go学习笔记之安装
    nginx学习笔记之安装
  • 原文地址:https://www.cnblogs.com/liudw-0215/p/9830975.html
Copyright © 2020-2023  润新知