上一篇数据结构与算法C++之插入排序中使用C++实现了插入排序算法,但是使用了交换操作(swap),一次swap操作包括三次移位操作,造成运行时间比较长,本篇博客对其改进。
(1)首先,考虑第一个元素8,此时只有一个元素,是排好序的
(2)然后考虑第二个元素6
(3)将元素6拷贝一份,保存起来
(4)此时比较元素6与前面的元素8的大小关系
(5)如果后面的元素6比前面元素8小,那么将前面的元素8向后移动一个位置,元素6向前移动一个位置
(6)此时已经是第一个位置了,前面没有元素了,就将元素6赋值给该位置,此时前两个元素已经排好序了
(7)再考虑下一个元素2,同样将元素2拷贝一份,保存起来,比较元素2和前面的元素8的大小关系
(8)此时2比8小,所以将8后移一个位置,然后指针向前移动
(9)此时2比前一个元素6小,所以将元素6向后移动一个位置,元素2向前移动一个位置
(10)此时已经是第一个元素,元素2没有前面的元素可比较的了,因此将2赋值给第一个位置
(11)以此类推,不使用swap操作,实现插入排序
C++程序实现为:
#include <iostream>
#ifndef _SORTINGHELP_H_
#define _SORTINGHELP_H_
#include "SortingHelp.h"
#endif // _SORTINGHELP_H_
using namespace std;
template<typename T>
void InsertionSortingImproved(T arr[], int n){
for (int i = 0; i < n - 1; i++){
T temp = arr[i+1];
int j;
for (j = i + 1; j > 0; j--){
if (arr[j-1] > temp){
arr[j] = arr[j-1];
}
else{
break;
}
}
arr[j] = temp;
}
return;
}
//template<typename T>
//void InsertionSortingImproved(T arr[], int n){
// for (int i = 1; i < n; i++){
// T temp = arr[i];
// int j;
// for (j = i; j > 0 && arr[j-1] > temp; j--){
// arr[j] = arr[j-1];
// }
// arr[j] = temp;
// }
//}
//int main(){
// int a[] = {10,9,8,6,6,5,5,3,2,2};
// int n = 10;
// InsertionSortingImproved(a, n);
// for(int i = 0; i < n; i++){
// cout<<a[i]<<" ";
// }
// cout<<endl;
// return 0;
//}
int main()
{
int n = 10000;
int *arr = generateRandomArray(n, 0, n);
int *arr2 = copyIntArray(arr, n);
testSorting("SelectionSorting", SelectionSorting, arr, n);
testSorting("InsertionSortingImproved", InsertionSortingImproved, arr2, n);
delete[] arr;//最后删除数组开辟的空间
delete[] arr2;
return 0;
}
上面程序中引用的一些函数在下面的头文件SortingHelp.h中,输出结果为
可以看出改进后的插入排序算法运行时间比选择排序要短了,证明改进有效
插入排序算法中,一个元素一旦找到合适的位置,那么排序操作就终止了,那么对于一个已经很有序的数组来讲(无序的元素比较少),大部分元素已经在合适的位置,所以它们的插入操作会很快就终止,因此在这种情况下插入排序算法的效率是很高的
为了很好的说明这个问题,我们创建一个近乎有序的数组放在SortingHelp.h文件中,然后进行运行时间比较,SortingHelp.h如下:
//SortingHelp.h
#include <iostream>
#include <ctime> //time()函数
#include <cstdlib> //rand()函数
#include <cassert> //assert()函数
using namespace std;
int* generateRandomArray(int n, int rangeL, int rangeR){//生成随机数组
assert(rangeL < rangeR);
int *arr = new int[n];
srand(time(NULL));
for (int i = 0; i < n; i++){
arr[i] = rand() % (rangeR - rangeL + 1) + rangeL;
}
return arr;
}
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 posx = rand() % n;
int posy = rand() % n;
swap(arr[posx], arr[posy]);
}
return arr;
}
template<typename T>
void printArray(T arr[], int n){//打印数组元素
for (int i = 0; i < n; i ++){
cout<<arr[i]<<" ";
}
cout<<endl; //换行
return;
}
template<typename 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<typename T>
void testSorting(string sortName, void(*sorting)(T[], int), T arr[], int n){//第二个参数是传入排序函数的指针
clock_t startClock = clock();
sorting(arr, n);
clock_t endClock = clock();
assert(isSorted(arr, n));
cout<<sortName<<" : "<<double(endClock-startClock)/CLOCKS_PER_SEC<<" s"<<endl;
return;
}
int* copyIntArray(int arr[], int n){
int* arr2 = new int[n];
copy(arr, arr+n, arr2);
return arr2;
}
template<typename T> //定义模板类型,使对各种数据类型都适用,如double,float,string
void SelectionSorting(T a[], int n){//选择排序算法
for (int i = 0; i < n; i++){
int minIndex = i;
for (int j = i + 1; j < n; j++){
if (a[j] < a[minIndex])
minIndex = j;
}
swap(a[i], a[minIndex]);
}
}
测试程序为
#include <iostream>
#ifndef _SORTINGHELP_H_
#define _SORTINGHELP_H_
#include "SortingHelp.h"
#endif // _SORTINGHELP_H_
using namespace std;
template<typename T>
void InsertionSortingImproved(T arr[], int n){
for (int i = 0; i < n - 1; i++){
T temp = arr[i+1];
int j;
for (j = i + 1; j > 0; j--){
if (arr[j-1] > temp){
arr[j] = arr[j-1];
}
else{
break;
}
}
arr[j] = temp;
}
return;
}
int main()
{
int n = 10000;
//int *arr = generateRandomArray(n, 0, n);
int *arr = generateNearlyOrderedArray(n, 100);//生成只有200个无序元素的数组
int *arr2 = copyIntArray(arr, n);
testSorting("SelectionSorting", SelectionSorting, arr, n);
testSorting("InsertionSortingImproved", InsertionSortingImproved, arr2, n);
delete[] arr;//最后删除数组开辟的空间
delete[] arr2;
return 0;
}
输出结果为
可以看出排序一个近乎有序的数组,插入排序只用了0.002s,对于近乎有序的数组来讲,插入排序算法的运行效率是很高的。