众所周知,最优的排序算法的复杂度是O(nlogn),但在学习最优算法前,我们先来看看O(n^2)复杂度的算法,由简入难。
算法描述:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
选择排序的代码:
void selectionSort(int 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[i] , arr[minIndex]);
}
}
选择排序的改进
为了让selectionSort()能接受不同类型(float,string ,char,或自定义类型)的数组,使用模板函数对其进行改进:
template
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[i] , arr[minIndex]);
}
}
随机生成数组
当采用的数组个数较大时,不可能一个一个的列举出来,这里编写一个随机生成数组的程序,用来辅助数组的排序。此处建立一个命名空间SortTestHelper,用来放与排序测试相关的各种函数,包括生产随机数组generateRandomArray()、printArray()、testSort()、isSorted()等。
generateRandomArray()的实现
//生成有n个元素的随机数组,每个元素的随机范围为[rangeL,rangeR]
int *generateRandomArray(int n, int rangeL, int rangeR)
{
assert(rangeL <= rangeR);//#include
int *arr = new int[n];
srand(time(NULL));//#include
for (int i = 0; i < n; i++)
{
arr[i] = rand() % (rangeR - rangeL + 1) + rangeL;
}
return arr;
}
测试代码如下:
#include
#include"SortTestHelper.h"
using namespace std;
template
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[i] , arr[minIndex]);
}
}
int main()
{
int n = 1000;
int *arr = SortTestHelper::generateRandomArray(n, 0, n);
selectionSort(arr, n);
for (int i = 0; i < n; i++)
{
cout << arr[i] << ",";
}
cout << endl;
delete[] arr;//注意要释放掉内存空间,否则发生内存泄漏
system("pause");
return 0;
}
上述打印过程也可放在SortTestHelper()命名空间中:
printArray()
void printArray(T arr[], int n)
{
for (int i = 0; i < n; i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
则测试代码重新写如下:
int n = 1000;
int *arr = SortTestHelper::generateRandomArray(n, 0, n);
selectionSort(arr, n);
SortTestHelper::printArray(arr, n);
delete[] arr;
如何衡量一个排序算法的性能?
算法在某个数据集上的执行时间可以衡量该算法的性能。接下来在SortTestHelper()空间中写一个衡量算法性能的函数testSort()
testSort()
//测试算法性能,传入的参数包括算法名称、算法函数本身,测试用例及用例长度
template
void testSort(string sortName, void(*sort)(T[], int),T arr[],int n)
{
//clock_t表示时钟周期的数据
clock_t startTime = clock();
sort(arr, n);
clock_t endTime = clock();
assert(isSorted(arr, n));
//两次时钟周期差表示算法真正执行的时钟周期,CLOCKS_PER_SEC每秒时钟周期个数
cout << sortName << double(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
return;
}
如何衡量排序算法的正确性?
代码如下:
isSorted()
//测试排序算法执行的正确性
template
bool isSorted(T arr[], int n)
{
for (int i = 0; i < n; i++)
{
if (arr[i] > arr[i + 1])
{
return false;
}
return true;
}
}
测试排序算法的性能
#include
#include"SortTestHelper.h"
using namespace std;
template
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[i] , arr[minIndex]);
}
}
int main()
{
int n = 10000;
int *arr = SortTestHelper::generateRandomArray(n, 0, n);
SortTestHelper::testSort("selectionSort:", selectionSort, arr, n);
delete[] arr;
system("pause");
return 0;
}
整个SortTestHelper()空间的代码如下:
#ifndef SELECTIONSORT_SORTTESTHELPER_H
#define SELECTIONSORT_SORTTESTHELPER_H
#include
#include
#include
#include
using namespace std;
namespace SortTestHelper
{
//生成有n个元素的随机数组,每个元素的随机范围为[rangeL,rangeR]
int *generateRandomArray(int n, int rangeL, int rangeR)
{
assert(rangeL <= rangeR);//#include
int *arr = new int[n];
srand(time(NULL));//#include
for (int i = 0; i < n; i++)
{
arr[i] = rand() % (rangeR - rangeL + 1) + rangeL;
}
return arr;
}
template
void printArray(T arr[], int n)
{
for (int i = 0; i < n; i++)
{
cout << arr[i] << " ,";
}
cout << endl;
return;
}
//测试算法执行的正确性
template
bool isSorted(T arr[], int n)
{
for (int i = 0; i < n; i++)
{
if (arr[i] > arr[i + 1])
{
return false;
}
return true;
}
}
//测试算法性能,传入的参数包括算法名称、算法函数本身,测试用例及用例长度
template
void testSort(string sortName, void(*sort)(T[], int),T arr[],int n)
{
//clock_t表示时钟周期的数据
clock_t startTime = clock();
sort(arr, n);
clock_t endTime = clock();
assert(isSorted(arr, n));
//两次时钟周期差表示算法真正执行的时钟周期,CLOCKS_PER_SEC每秒时钟周期个数
cout << sortName << double(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
return;
}
}
#endif
说明:本文是在听了波波老师的数据结构算法课程后所做的笔记!