排序算法(2)——插入排序以及其优化形式

插入排序理解

插入排序顾名思义就是指的在一组数据中,在合适的位置插入元素,插入排序类似整理扑克牌,将每一张牌插到其他已经有序的牌中适当的位置。插入排序的基本思想就是从i=1号下标元素开始,和之前的元素进行比较,例如升序,若出现i之前的数比i大则需要进行交换位置,然后内层循环递减,直到第一个元素,因此相当于有两层循环,外层循环控制只需要比较n-1次,令内层循环的j 的起点和i 相同,j递减 ,两两比较。

 

具体代码下:

template<class T>
void InsertionSort1(T arr[],int n)
{
    for(int i = 1;i<n;i++) //i从1开始 第一个元素不需要动
    {  //寻找arr[i]合适的插入位置
        for(int j = i;j>0&& arr[j] < arr[j-1];j--) //当前位置向之前推导 注意 这里j不需要取到0 不然j-1取到-1了
        {
            //if(arr[j] < arr[j-1])
                swap(arr[j], arr[j-1]); //比前一个位置的元素小 进行交换
        }
    }
    return;
}

插入排序的改进

但是这种写法,在每一轮循环都需要进行大量的交换操作,会导致程序运行效率下降,因为一次数据交换涉及到一个中间变量的产生;因此可以对上述的算发进行改进,可以和选择排序交换的优化目标一样,减少交换次数;因此在改进版本可以对一个变量进行复制,然后依次和之前位置比,例如假设开始起点在i = j位置,将arr[i]复制出来一份 给temp;然后将i之前的数据和temp比较,在升序过程中,出现i 之前的数字比temp大的数,则将arr[j-1]上的数字赋值给arr[j-1]位置,紧接着往下递减进行,出现arr[j-1]位置比temp小时切j>0,将arr[j] = temp;此时的位置就是temp的位置;

具体代码如下:

template<class T>
void InsertionSort2(T arr[],int n)
{
    for(int i = 1;i<n;i++) //i从1开始 第一个元素不需要动
    {  //寻找arr[i]合适的插入位置
        T temp = arr[i];
        int j;
        for(j = i;j>0 && arr[j-1] > temp;j--) //当前位置向之前推导 注意 这里j不需要取到0 不然j-1取到-1了 能否插入到位置 看前一个元素
        {
                arr[j] = arr[j-1];
        }
        arr[j] = temp; //此时的j的位置就是 temp该插入的位置
    }
    return;
}

总结:插入排序的时间复杂度为o(n^2),但是第二种性能要比之前的号一些,而且插入排序的算发整体上都要比选择排序的算法好一些,尤其是在数组维度比较小,近似趋于有序的数组排序,插入排序的算发优越性比选择排序好,而且后面插入排序还引申出了希尔排序算法,下一讲会介绍到。

整体代码

main.cpp

//  Copyright © 2018 zifengxu. All rights reserved.
//
/*
 插入排序算法;InsertionSort1 每一次遍历都在做交换 因此时间复杂度会增加 拖慢程序
 可以进行改进:改进版本将i位置的值 拷贝一份出来temp 然后依次往前推 j--位置如果比 temp大
 往后一个位置 复制 直到j>0 0位置 或者遇到比temp小的 值 停下来 此时的j位置就是temp的位置
 */

#include <iostream>
#include "SortTestHelper.h"
#include "SelectionSort.h"

using namespace std;

template<class T>
void InsertionSort1(T arr[],int n)
{
    for(int i = 1;i<n;i++) //i从1开始 第一个元素不需要动
    {  //寻找arr[i]合适的插入位置
        for(int j = i;j>0&& arr[j] < arr[j-1];j--) //当前位置向之前推导 注意 这里j不需要取到0 不然j-1取到-1了
        {
            //if(arr[j] < arr[j-1])
                swap(arr[j], arr[j-1]); //比前一个位置的元素小 进行交换
        }
    }
    return;
}


//经过改进之后的插入排序
template<class T>
void InsertionSort2(T arr[],int n)
{
    for(int i = 1;i<n;i++) //i从1开始 第一个元素不需要动
    {  //寻找arr[i]合适的插入位置
        T temp = arr[i];
        int j;
        for(j = i;j>0 && arr[j-1] > temp;j--) //当前位置向之前推导 注意 这里j不需要取到0 不然j-1取到-1了 能否插入到位置 看前一个元素
        {
                arr[j] = arr[j-1];
        }
        arr[j] = temp; //此时的j的位置就是 temp该插入的位置
    }
    return;
}



int main(int argc, const char * argv[]) {
    // insert code here...
    int n = 20;
    int*arr = SortTestHelper::generateRandArray(n,0,n);
    int*arr1 = SortTestHelper::copyArray(arr,n);
    
    
    SortTestHelper::testSort("InsertionSort", InsertionSort2, arr, n); //插入排序
    SortTestHelper::testSort("SelectionSort", selectionSort1, arr1, n); //选择排序
    
    SortTestHelper::printArray(arr, 20);
    
    delete[] arr;
    delete[] arr1;
    
    cout<<endl;
    std::cout << "Hello, World!\n";
    
    return 0;
}

SortTestHelper.h

#ifndef SortTestHelper_h
#define SortTestHelper_h

#include <iostream>
#include <time.h>
#include <ctime>
#include <cassert>
#include <string>


namespace SortTestHelper {
    //生成随机数
    int* generateRandArray(int n, int rangeL, int rangeR)
    {
        assert(rangeL <= rangeR);
        int *arr =  new int [n];
        std::srand(time(NULL));
        for(int i = 0;i<n;i++)
        {
            arr[i] = int(rand()%(rangeR - rangeL + 1) + rangeL);
        }
        return arr;
    }
    //打印元素
    template <class T> void printArray(T Arr[],int n)
    {
        for(int i = 0;i<n;i++)
        {
            std::cout<<*(Arr + i)<<" ";
        }
    }
    
    template<class 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<class T>
    void testSort(std::string sortname,void(*sort)(T [],int),T arr[],int n)
    {
        clock_t starTime = clock();
        sort(arr,n);
        clock_t endTime = clock(); //计算排序时间
        
        assert(isSorted(arr,n));
        std::cout<<sortname<<":"<<double(endTime - starTime)/CLOCKS_PER_SEC<<"S"<<std::endl;
        //计算排序的时间d多少
        return;
    }
    
    //template <class T> //数组拷贝
    int* copyArray(int arr[],int n)
    {
        int* arr1 = new int[n];
        std::copy(arr,arr+n,arr1);
        return arr1;
    }

}

#endif /* SortTestHelper_h */

SelectionSort.h

#ifndef SelectionSort_h
#define SelectionSort_h

#include <iostream>
#include <algorithm>
#include <time.h>

using namespace std;


template <class T>
void  selectionSort1(T arr[],int N)
{
    //T temp = 0;
    for (int i = 0;i<N-1;i++)  // 只需比较N-1次
    {
        for (int j = i + 1;j<N;j++)
        {
            if(arr[i] > arr[j]) // 又出现比选择的数 大或者小的进行交换
            {
                // temp = arr[i];  // 进行交换
                //arr[i] = arr[j];
                //arr[j] = temp;
                swap(arr[i], arr[j]);
            }
        }
    }
}

template <class T>
void  selectionSort2(T arr[],int n)
{
    // T temp;
    for (int i = 0;i<n;i++)
    {
        int minIndex = i; //选择待比较的值
        for(int j = i + 1;j < n;j++)
        {
            if(arr[j] < arr[minIndex])
            {
                minIndex = j;
            }
        }
        //temp = arr[i]; //交换这里的时间复杂度相当于O(n)每一轮就进行一次比较
        //arr[i] = arr[minIndex];
        //arr[minIndex] = temp;
        swap(arr[i], arr[minIndex]);
    }
}

#endif /* SelectionSort_h */

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值