数据结构算法学习总结-慕课网(四)插入排序的优化(从小到大)
1.回顾
插入排序
template<typename T>
void insertSort(T arr[],int n){
for(int i = 1;i<n;i++){
for(int j = i;j>0;j--){
if(arr[j] < arr[j-1]){
swap(arr[j],arr[j-1]);
}else{
break;
}
}
}
}
选择排序
template<typename T>
void selectionSort(T arr[],int n){
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;
}
}
swap(arr[minIndex],arr[i]);//把a,b交换位置
}
}
上一节讲到插入排序的最基本的实现,最后测试了插入排序和选择排序所花的时间,发现插入排序虽然可以提前结束第二层循环,但是时间却比选择排序花的更多,看起来插入排序的性能好像不咋的?
介于此,这章节将会讲插入排序的优化,之后就可以明显感觉到对于一个近乎有序的数组,插入排序的性能将会特别高
2.思考
1.首先了解swap函数,对它有了解的同学知道,swap函数交换数组的位置,其实要经过三次赋值,虽然我们提前结束了第二层循环,但是swap这个地方可能需要优化一下
2.如果我们把swap换做一次赋值的话,那么插入排序的性能会得到很好的提升
3.思路
假设有{5,4,8}这样的数组,我们知道角标是0,1,2,0位置元素不动,对于1位置的元素4,首先复制一份值,然后与前一位0位置的值5进行比较,发现5比4要大,那么把5后移一位,现在数组变成[5,5,8],然后将最后保存1位置的元素4赋值给1位置现在的元素5,那么数组变成[4,5,8],往后的类似
4.实战
InsertSort.cpp
#include <iostream>
#include "SortTestHelper.h"
#include "SelectionSort.h"
using namespace std;
template<typename T>
void insertSort(T arr[],int n){
for(int i = 1;i<n;i++){
T e = arr[i];
int j;
for(j = i;j>0 && arr[j-1] > e;j--){
arr[j] = arr[j-1];
}
arr[j] = e;
}
}
int main(){
int n = 100000;
int* arr = SortTestHelper::generateRandomArray(n,0,100);
int* arr2 = SortTestHelper::copyArray(arr,n);
SortTestHelper::testSort("Insert Sort :",insertSort,arr,n);
SortTestHelper::testSort("Select Sort :",selectionSort,arr,n);
delete [] arr;
delete [] arr2;
return 0;
}
SelectionSort.h
#include <iostream>
#include "Student.h"
#include "SortTestHelper.h"
using namespace std;
/**
* 选择排序
*/
template<typename T>
void selectionSort(T arr[],int n){
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;
}
}
swap(arr[minIndex],arr[i]);//把a,b交换位置
}
}
SortTestHelper.h
#ifndef SORTTESTHELPER_H_
#define SORTTESTHELPER_H_
#include <iostream>
#include <ctime>
#include <cassert>
using namespace std;
namespace SortTestHelper{
//生成n个元素的随机数组,每个元素的随机范围为[rangeL,rangeR]
int* generateRandomArray(int n,int rangeL,int rangeR){
assert(rangeL <= rangeR); //为了程序稳定性,如果rangeL>rangeR,那么程序不会往下执行
int *arr = new int[n];
srand(time(NULL));//随机种子,需要导入ctime库
for(int i = 0;i<n;i++){
arr[i] = rand() % (rangeR - rangeL + 1) + rangeL; //自己可以动笔算一下
}
return arr;
}
/**
* 检验排序的正确性
*/
template<typename T>
bool isSorted(T arr[],int n){
for(int i = 0;i<n;i++){
//注意,如果i=n-2时,实际上会比较arr[n-2]和arr[n-1]的值,此时数组已经比较完毕
if(i<n-1 && arr[i]>arr[i+1]){
return false;
}
}
return true;
}
/**
* 测试排序所需要的时间
*/
template<typename T>
void testSort(string sortName,void(*sort)(T arr[],int n),T arr[],int n){
clock_t startTime = clock();
sort(arr,n);
clock_t endTime = clock();
assert(isSorted(arr,n));
cout <<sortName<<" : "<< double(endTime - startTime) /CLOCKS_PER_SEC <<"s" << endl;
return;
}
template<typename T>
void printArray(T arr[],int n){
for(int i = 0;i<n;i++)
cout << arr[i] << " "; //循环打印数组中的元素
cout << endl;
}
int* copyArray(int arr[],int n){
int* b = new int[n];
//拷贝数组参数:指针开始的位置;指针结束的位置;目标数组
copy(arr,arr+n,b);
return b;
}
/**
*生成一个近乎有序的数组
*/
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 swapX = rand()%n;
int swapY = rand()%n;
swap(arr[swapX],arr[swapY]);
}
return arr;
}
}
#endif /* SORTTESTHELPER_H_ */
运行结果
Insert Sort : : 6.264sSelect Sort : : 12.44s
总结
从结果可以知道,10w级别的测试数据量,对于一个近乎有序的数组,插入排序的性能明显比选择排序要高
意见与建议
如果博友有任何问题或者建议,欢迎留言讨论