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

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

上一篇資料結構與演算法C++之插入排序中使用C++實現了插入排序演算法,但是使用了交換操作(swap),一次swap操作包括三次移位操作,造成執行時間比較長,本篇部落格對其改進。
(1)首先,考慮第一個元素8,此時只有一個元素,是排好序的
在這裡插入圖片描述
(2)然後考慮第二個元素6
在這裡插入圖片描述
(3)將元素6拷貝一份,儲存起來
在這裡插入圖片描述
(4)此時比較元素6與前面的元素8的大小關係
在這裡插入圖片描述
(5)如果後面的元素6比前面元素8小,那麼將前面的元素8向後移動一個位置,元素6向前移動一個位置
在這裡插入圖片描述
(6)此時已經是第一個位置了,前面沒有元素了,就將元素6賦值給該位置,此時前兩個元素已經排好序了
在這裡插入圖片描述
(7)再考慮下一個元素2,同樣將元素2拷貝一份,儲存起來,比較元素2和前面的元素8的大小關係


在這裡插入圖片描述
(8)此時2比8小,所以將8後移一個位置,然後指標向前移動
在這裡插入圖片描述
(9)此時2比前一個元素6小,所以將元素6向後移動一個位置,元素2向前移動一個位置
在這裡插入圖片描述
(10)此時已經是第一個元素,元素2沒有前面的元素可比較的了,因此將2賦值給第一個位置
在這裡插入圖片描述
(11)以此類推,不使用swap操作,實現插入排序

C++程式實現為:

#include <iostream>

#ifndef _SORTINGHELP_H_
#define _SORTINGHELP_H_

#include "SortingHelp.h"

#endif // _SORTINGHELP_H_

using namespace std;
template<typename T> void InsertionSortingImproved(T arr[], int n){ for (int i = 0; i < n - 1; i++){ T temp = arr[i+1]; int j; for (j = i + 1; j > 0; j--){ if (arr[j-1] > temp){ arr[j] = arr[j-1]; } else{ break
; } } arr[j] = temp; } return; } //template<typename T> //void InsertionSortingImproved(T arr[], int n){ // for (int i = 1; i < n; i++){ // T temp = arr[i]; // int j; // for (j = i; j > 0 && arr[j-1] > temp; j--){ // arr[j] = arr[j-1]; // } // arr[j] = temp; // } //} //int main(){ // int a[] = {10,9,8,6,6,5,5,3,2,2}; // int n = 10; // InsertionSortingImproved(a, n); // for(int i = 0; i < n; i++){ // cout<<a[i]<<" "; // } // cout<<endl; // return 0; //} int main() { int n = 10000; int *arr = generateRandomArray(n, 0, n); int *arr2 = copyIntArray(arr, n); testSorting("SelectionSorting", SelectionSorting, arr, n); testSorting("InsertionSortingImproved", InsertionSortingImproved, arr2, n); delete[] arr;//最後刪除陣列開闢的空間 delete[] arr2; return 0; }

上面程式中引用的一些函式在下面的標頭檔案SortingHelp.h中,輸出結果為
在這裡插入圖片描述
可以看出改進後的插入排序演算法執行時間比選擇排序要短了,證明改進有效
插入排序演算法中,一個元素一旦找到合適的位置,那麼排序操作就終止了,那麼對於一個已經很有序的陣列來講(無序的元素比較少),大部分元素已經在合適的位置,所以它們的插入操作會很快就終止,因此在這種情況下插入排序演算法的效率是很高的
為了很好的說明這個問題,我們建立一個近乎有序的陣列放在SortingHelp.h檔案中,然後進行執行時間比較,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;
}

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;
}


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>

#ifndef _SORTINGHELP_H_
#define _SORTINGHELP_H_

#include "SortingHelp.h"

#endif // _SORTINGHELP_H_

using namespace std;

template<typename T>
void InsertionSortingImproved(T arr[], int n){
    for (int i = 0; i < n - 1; i++){
        T temp = arr[i+1];
        int j;
        for (j = i + 1; j > 0; j--){
            if (arr[j-1] > temp){
                arr[j] = arr[j-1];
            }
            else{
                break;
            }
        }
        arr[j] = temp;
    }
    return;
}
int main()
{
    int n = 10000;
    //int *arr = generateRandomArray(n, 0, n);
    int *arr = generateNearlyOrderedArray(n, 100);//生成只有200個無序元素的陣列
    int *arr2 = copyIntArray(arr, n);
    testSorting("SelectionSorting", SelectionSorting, arr, n);
    testSorting("InsertionSortingImproved", InsertionSortingImproved, arr2, n);
    delete[] arr;//最後刪除陣列開闢的空間
    delete[] arr2;
    return 0;
}

輸出結果為
在這裡插入圖片描述
可以看出排序一個近乎有序的陣列,插入排序只用了0.002s,對於近乎有序的陣列來講,插入排序演算法的執行效率是很高的。