插入排序理解
插入排序顾名思义就是指的在一组数据中,在合适的位置插入元素,插入排序类似整理扑克牌,将每一张牌插到其他已经有序的牌中适当的位置。插入排序的基本思想就是从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;
}
总结:插入排序的时间复杂度为,但是第二种性能要比之前的号一些,而且插入排序的算发整体上都要比选择排序的算法好一些,尤其是在数组维度比较小,近似趋于有序的数组排序,插入排序的算发优越性比选择排序好,而且后面插入排序还引申出了希尔排序算法,下一讲会介绍到。
整体代码
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 */