1. 程式人生 > >資料結構與演算法C++之插入排序

資料結構與演算法C++之插入排序

本篇實現的是插入排序,其演算法複雜度是O(n2),插入排序的原理來自部落格
插入排序原理很簡單,將一組資料分成兩組,分別將其稱為有序組與待插入組。左邊為有序組,右邊為待插入組,每次從待插入組中取出一個元素,與有序組的元素進行比較,並找到合適的位置,將該元素插到有序組當中。就這樣,每次插入一個元素,有序組增加,待插入組減少。直到待插入組元素個數為0。當然,插入過程中涉及到了元素的移動。為了排序方便,一般將資料第一個元素視為有序組,其他均為待插入組。然後有序組元素慢慢增加,待插入組元素慢慢減少,原理圖如下
插入排序原理圖
下面是C++實現:

#include <iostream>

using namespace std;
template<typename T> void InsertionSorting(T arr[], int n){ for (int i = 0; i < n - 1; i++){ for (int j = i + 1; j > 0; j--){ if (arr[j-1] > arr[j]){ swap(arr[j-1], arr[j]); } else break; } } return
; } int main(){ int a[] = {10,9,8,7,6,5,4,3,2,1,0}; int n = 11; InsertionSorting(a, n); for(int i = 0; i < n; i++){ cout<<a[i]<<" "; } cout<<endl; return 0; }

輸出結果為:
在這裡插入圖片描述
上面只是簡單的實現了11個元素排序,下面我們編寫一個含有自動生成陣列的函式、列印輸出函式、複製陣列函式、測試排序函式正確性、計時的標頭檔案SortingHelp.h,來測試插入排序演算法和

上一篇的選擇排序演算法

//SortingHelp.h

#include <iostream>
#include <ctime>  //time()函式
#include <cstdlib> //rand()函式
#include <cassert> //assert()函式


using namespace std;

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<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 testSorting(string sortName, void(*sorting)(T[], int), T arr[], int n){//第二個引數是傳入排序函式的指標

    clock_t startClock = clock();
    sorting(arr, n);
    clock_t endClock = clock();
    assert(isSorted(arr, n));
    cout<<sortName<<" : "<<double(endClock-startClock)/CLOCKS_PER_SEC<<" s"<<endl;
    return;
}

int* copyIntArray(int arr[], int n){
    int* arr2 = new int[n];
    copy(arr, arr+n, arr2);
    return arr2;
}

template<typename T> //定義模板型別,使對各種資料型別都適用,如double,float,string
void SelectionSorting(T a[], int n){//選擇排序演算法
    for (int i = 0; i < n; i++){
        int minIndex = i;
        for (int j = i + 1; j < n; j++){
            if (a[j] < a[minIndex])
                minIndex = j;
        }
        swap(a[i], a[minIndex]);
    }
}

測試程式為:

#include <iostream>
#include "SortingHelp.h"

using namespace std;

template<typename T>
void InsertionSorting(T arr[], int n){
    for (int i = 0; i < n - 1; i++){
        for (int j = i + 1; j > 0; j--){
            if (arr[j-1] > arr[j]){
                swap(arr[j-1], arr[j]);
            }
            else
                break;
        }
    }
    return;
}

int main()
{
    int n = 10000;
    int *arr = generateRandomArray(n, 0, n);
    int *arr2 = copyIntArray(arr, n);
    testSorting("SelectionSorting", SelectionSorting, arr, n);
    testSorting("InsertionSorting", InsertionSorting, arr2, n);
    delete[] arr;//最後刪除陣列開闢的空間
    delete[] arr2;
    return 0;
}

輸出為
在這裡插入圖片描述
因為在插入排序中用了交換swap操作,每次swap需要三次賦值,而每次移動操作只需要一次賦值,所以插入操作的執行時間比選擇排序長一些。