1

插入排序法(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;
}

songjie4590
4 声望0 粉丝