基础排序算法
下面分别列举了选择排序、插入排序、冒泡排序和希尔排序三种排序方法。
在下面的插入排序中,我做了很大改进,放弃了采用交换的方式,因为swap的效率太低了,所以我们改用挨个移位,在移动不了的情况之下进行复制的方法。
// used for test
// Created by lizeyi on 2020/11/16.
//
#ifndef ALGROTHIM_SORTTESTHELPER_H
#define ALGROTHIM_SORTTESTHELPER_H
#include <cstdlib>
#include <vector>
#include <iostream>
#include <ctime>
#include <cassert>
using namespace std;
namespace SortTestHelper{
//插入排序
template<typename T>
void insertSort(T arr[],int n){
//在这边 插入排序的第0个元素就不用考虑了,每一次把当前位置的元素和前一个元素作比较
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;
}
}
//选择排序
template<typename T>
void selectionSort(T arr[],int n){
for (int i = 0; i < n; ++i) {
//寻找【i , n】区间里的最小值
int minIndex = i;
for (int j = i+1; j < n; ++j) {
if (arr[j]<arr[minIndex])
minIndex = j;
}
swap(arr[i],arr[minIndex]);
}
}
// 冒泡排序
template<typename T>
void bubbleSort( T arr[] , int n){
bool swapped;
//int newn; // 理论上,可以使用newn进行优化,但实际优化效果较差
do{
swapped = false;
//newn = 0;
for( int i = 1 ; i < n ; i ++ )
if( arr[i-1] > arr[i] ){
swap( arr[i-1] , arr[i] );
swapped = true;
// 可以记录最后一次的交换位置,在此之后的元素在下一轮扫描中均不考虑
// 实际优化效果较差,因为引入了newn这个新的变量
//newn = n;
}
//n = newn;
// 优化,每一趟Bubble Sort都将最大的元素放在了最后的位置
// 所以下一次排序,最后的元素可以不再考虑
// 理论上,newn的优化是这个优化的复杂版本,应该更有效
// 实测,使用这种简单优化,时间性能更好
n --;
}while(swapped);
}
// 希尔排序(插入排序的改进版)
template<typename T>
void shellSort(T arr[], int n){
int h = 1;
while( h < n/3 )
h = 3 * h + 1;
// 计算 increment sequence: 1, 4, 13, 40, 121, 364, 1093...
while( h >= 1 ){
// h-sort the array
for( int i = h ; i < n ; i ++ ){
// 对 arr[i], arr[i-h], arr[i-2*h], arr[i-3*h]... 使用插入排序
T e = arr[i];
int j;
for( j = i ; j >= h && e < arr[j-h] ; j -= h )
arr[j] = arr[j-h];
arr[j] = e;
}
h /= 3;
}
}
// 1 return new array. number is n . range from rangeL to rangeR [rangeL,rangR]
template<typename T>
int *generateRandomArray(int n , int rangeL , int rangeR){
assert(rangeL<rangeR);
T *arr = new T[n];
// 根据时间 设置随机种子
srand(time(NULL));
for (int i = 0;i<n;i++){
arr[i] = rand() % (rangeR-rangeL+1) + rangeL ;
}
return arr;
}
//生成一个近乎有序的数组int类型 swapTimes交换的次数
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;
}
// 2 打印函数
template<typename T>
void printArray(T arr[],int n){
for (int i = 0; i < n; ++i) {
cout<<arr[i]<<" ";
cout<<endl;
}
return;
}
// 4 判断是否是已排序的
template <typename T>
bool isSort(T arr[],int n){
for (int i = 0;i<n-1;i++){
if (arr[i] > arr[i+1]){
return false;
}
}
return true;
}
//3 计算排序时间
template<typename T>
void testSort(string sortName, void(* sort) (T [],int ),T arr[],int n){
clock_t startTime = clock();
sort(arr,n);
clock_t endTime = clock();
assert(isSort(arr,n));
cout<<sortName<<":"<<double(endTime-startTime) / CLOCKS_PER_SEC<<"s"<<endl;
return;
}
// 拷贝一个数组,不适用于拷贝一个对象 只能用于int string double
template<typename T>
T* copyIntArray(T a[],int n){
static_assert(sizeof(int) == sizeof(T) || sizeof(string) == sizeof(T) || sizeof(double) == sizeof(T),
"T type is not the specified DataType including int and float");
T* arr = new T[n];
// 拷贝原地址的头指针a,一个尾指针a+n ,目的地址的头指针
copy(a,a+n,arr);
return arr;
}
}
#endif //ALGROTHIM_SORTTESTHELPER_H
参考文献
[1]维基百科.排序算法[EB/OL].https://zh.wikipedia.org/wiki/排序算法,2013-11-01.