插入排序法(Insertion Sort)
一,概念
-
自行總結:當前元素小於(大於)前一個元素,則當前元素就插入到前一個元素之前,直到排序完成
-
區別:
- 插入排序:二層循環可以提前結束循環
- 選擇排序:二層循環要全部執行
-
時間複雜度:O(n2)
-
特點:如果待排序數組近乎有序,那可以很快結束二層循環,時間複雜度趨於O(n)
二,圖示
更接近,插入排序改進方法的邏輯
三,C++實現
main.cpp
#include <iostream>
#include <algorithm>
#include "SortTestHelper.h"
#include "SelectionSort.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] );
}
return;
}
int main() {
int n = 10000;
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;
return 0;
}
SortTestHelper.h
int *copyIntArray(int a[], int n){
int *arr = new int[n];
copy(a, a+n, arr);
return arr;
}
四,js實現
// 插入排序
function insertionSort(arr, n){
for(let i = 1; i < n; i++){
// 尋找元素arr[i]合適的插入位置(和之前元素進行比較)
// 插入排序的二層循環可以提前結束,但選擇排序的二層循環要完整執行找到最小值
for(let j = i; j > 0; j--){
if(arr[j]< arr[j-1]){
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}else{
break;
}
}
}
return arr;
}
// 生成隨機數組
function getRandom(n){
let arr = [];
for (let i = 0; i < n; i++){
arr[i] = Math.floor(Math.random() * n);
}
return arr;
}
insertionSort(getRandom(100),100);
五,排序時間比較
選擇排序比插入排序時間短
。插入排序雖然能提前結束循環,但是一直交換賦值。而選擇排序每次只有一次交換。
c++
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);
js
let arr1 = getRandom(100);
// copy數組
let arr2 = [...arr1];
console.time("sort");
selectionSort(arr1,100);
console.timeEnd("sort");
console.time("sort");
insertionSort(arr2,100);
console.timeEnd("sort");
六,插入排序改進
問題:對於插入排序多次交換賦值的缺點,能不能改成一次賦值?
自行總結:把待插入的元素拿出,向前比較,比它大的元素後移,直到找到自己的位置,一次插入。
c++
void insertionSort(T arr[], int n){
for( int i = 1 ; i < n ; i ++ ) {
// 寫法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;
}
js
// 插入排序
function insertionSort(arr, n){
for(let i = 1; i < n; i++){
let e = arr[i];// 把待插入的元素拿出
let j = 0; // j保存元素e應該插入的位置
for(j = i; j > 0; j--){
if(e < arr[j-1]){ // 元素e向前比較
arr[j] = arr[j-1];// 大於e的元素後移
}else{
break;
}
}
// 當循環終止時(e > arr[j-1]),e找到自己位置爲j
arr[j] = e;
}
return arr;
}