資料結構與演算法C++之插入排序(續)
阿新 • • 發佈:2018-11-14
上一篇資料結構與演算法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,對於近乎有序的陣列來講,插入排序演算法的執行效率是很高的。