排序算法的比较---插入、选择、快排
实验代码:
#include<iostream>
#include<cstdlib>
#include<time.h>
#define N 100000
using namespace std;
class Array
{
public: Array(); //构造函数
void Sort_decent(); //辅助构造函数产生非递增序列
void Sort_one(); //排序方案一:插入排序
void Sort_two(); //排序方案二:选则排序
void Sort_three_SampleOne(int *Sample,int start,int end); //排序方案三:快速排序
void Sort_three_SampleOne_time(); //为乱序数组快排计时
void Sort_three_SampleTwo_time(); //为顺序数组快排计时
private: void Show_result(int *p); //如果需要可以使用来显示排序结果:
//因为测试数据数量较多,所以略去这一步
//小规模测试可以考虑使用(后面给出了其代码实现)
int sarray[N]; //随机数组
int darray[N]; //非递增数组
};
Array::Array()
{
for(int i=0;i<N;i++) //产生随机数组
{
srand(i);
sarray[i] = darray[i] = rand()%N;
}
Sort_decent(); //将数组darray非递增排序
}
void Array::Sort_decent()
{
int temp;
for(int i=0;i<N-1;i++)
{
for(int j=i;j<N;j++)
if(darray[i]<darray[j])
{
temp = darray[i];
darray[i] = darray[j];
darray[j] = temp;
}
}
}
void Array::Sort_one() //排序方案一:插入排序
{ int Sample_one[N];
int Sample_two[N]; //样本数组:sarray与darray的两个样本,下同
int i,j,k,l;
for( i=0 ;i<N;i++)
{
Sample_one[i] = sarray[i];
Sample_two[i] = darray[i];
}
clock_t start1 = clock(); //记录排序起始时间,下同
for( j=1;j<N;j++ ) //对乱序数组排序
{
k = Sample_one[j];
l = j-1;
while((k>=0)&&(Sample_one[l]>k))
{
Sample_one[l+1] = Sample_one[l];
l--;
}
Sample_one[l+1] = k;
}
clock_t end1=clock(); //记录排序终了时间,下同
// Show_result(Sample_one);
cout<<"乱序数组插入排序用时: "<<end1-start1<<" ms"<<endl;
// Show_result(Sample_two);
clock_t start2=clock();
for( j=1;j<N;j++ ) //对顺序数组排序
{
k = Sample_two[j];
l = j-1;
while((k>=0)&&(Sample_two[l]>k))
{
Sample_two[l+1] = Sample_two[l];
l--;
}
Sample_two[l+1] = k;
}
clock_t end2=clock();
// Show_result(Sample_two);
cout<<"顺序数组插入排序用时: "<<end2-start2<<" ms"<<endl;
}
void Array::Sort_two() //排序方案二:选择排序
{
int Sample_one[N];
int Sample_two[N];
int i;
for( i=0 ;i<N;i++)
{
Sample_one[i] = sarray[i];
Sample_two[i] = darray[i];
}
clock_t start1 = clock();
for ( i = 0; i < N; i++)
{
int min = Sample_one[i], min_index = i;
for (int j = i; j < N; j++)
{
if (Sample_one[j] < min)
{
min = Sample_one[j];
min_index = j;
}
}
if (min_index != i)
{
int temp = Sample_one[i];
Sample_one[i] = Sample_one[min_index];
Sample_one[min_index] = temp;
}
}
clock_t end1=clock();
// Show_result(Sample_one);
cout << "乱序数组选择排序用时: "<<end1-start1<<" ms"<<endl;
clock_t start2 = clock();
for( i=0; i < N; i++)
{
int min = Sample_two[i], min_index = i;
for (int j = i; j < N; j++)
{
if (Sample_two[j] < min)
{
min = Sample_two[j];
min_index = j;
}
}
if (min_index != i)
{
int temp = Sample_two[i];
Sample_two[i] = Sample_two[min_index];
Sample_two[min_index] = temp;
}
}
clock_t end2=clock();
// Show_result(Sample_two);
cout<<"顺序数组选择排序用时: "<<end2-start2<<" ms"<<endl;
}
void Array::Sort_three_SampleOne(int *Sample_one,int start,int end) //排序方案三:快速排序
{
int i,j,std_data;
if(start < end)
{ //第一趟排序
i = start;
j = end;
std_data = Sample_one[start];
while(i<j)
{
while(Sample_one[j]>=std_data&&i<j)
{
j--;
}
if(i<j) Sample_one[i++] = Sample_one[j];
while(Sample_one[i]<=std_data&&i<j)
{
i++;
}
if(i<j) Sample_one[j--] = Sample_one[i];
}
Sample_one[i] = std_data;
Sort_three_SampleOne(Sample_one,start,i-1);
Sort_three_SampleOne(Sample_one,i+1,end);
}
}
void Array::Sort_three_SampleOne_time() //记录乱序数组排序时间
{
int Sample_one[N];
for(int i=0 ;i<N;i++)
{
Sample_one[i] = sarray[i];
}
clock_t start1 = clock();
Sort_three_SampleOne(Sample_one,0,N-1);
clock_t end1 = clock();
cout<<"乱序数组快速排序用时: "<<end1-start1<<" ms"<<endl;
}
void Array::Sort_three_SampleTwo_time() //记录顺序数组排序时间
{
int Sample_two[N];
for(int i=0 ;i<N;i++)
{
Sample_two[i] = darray[i];
}
clock_t start2 = clock();
Sort_three_SampleOne(Sample_two,0,N-1);
clock_t end2 = clock();
cout<<"顺序数组快速排序用时: "<<end2-start2<<" ms"<<endl;
}
void Array::Show_result(int *p)
{
for(int i=0;i<N;i++)
cout<<p[i]<<"\t";
}
int main(void)
{
Array array;
array.Sort_one();
array.Sort_two();
array.Sort_three_SampleOne_time();
array.Sort_three_SampleTwo_time();
return 0;
}
代码在Vs2012上编译运行通过,运行时可自行修改N的值从而改变排序规模
总结:
(1)算法部分:
这个程序的编写是用面向对象的思想进行的,Array类有Sort_one()
Sort_two()、Sort_three()三个行为即插入、选择、快速排序以及两个数组成员sarray,darray.从数据结构方面的知识我们知道插入排序的时间复杂度为O(n^2),从实验结果可以看出它并不适合数据量很大的排序,而选择排序与插入排序的时间复杂度同为O(n^2)所以也不适合大量数据的排序,但是从截图可以看出在乱序数组排序时,插入排序较选择排序更具有优势,快速排序对乱序数组的排序具有十分明显的优势,其时间复杂度为O(nLogn),从实验结果来看也的确如此,随着数据量的增大快排很显然是最好的选择,但是也该注意到快排对于顺序数组的排序时间复杂度的数量级也是O(n^2),所以具体使用哪种排序方式还得具体情况具体分析。
(2)类的设计部分:
之前有考虑将排序前后的结果输出,但是实验要求是测试大规模数据的排序,所以数组的输出会使得结果显得十分累赘而没有突出重点,但还是给出了其实现,所以Array类的Show_result()成员,仅供使用者依据需要自行使用(最好用于小规模的数据输出)。另外的不足之处在于,Sort_one()、Sort_two()、Sort_three()三个成员都要对sarray与darray两个私有成员中的数据进行处理,可谓“僧多粥少”,所以在设计时每个方法都定义了两个局部变量Sample_one与Sample_two用于复制sarray与darray,但是这样无疑是中糟糕的方案,其实自己的想法是每个成员处理了数组之后能够将其复原,这样可以节省内存分配所用时间,但是知识与技术有限,没能这样实现,所以以后还得更加努力学习C++面向对象的编程思想。
(3)错误经验分析:
在程序结果正确输出前,犯了一个十分严重的错误,就是未意识到快速排序的递归性,而将时间测量也放在了快排函数的实现中,而结果输出出错。就这点我深刻意识到了递归函数的功能一定要是十分单一的,只能解决一个问题,不断将其规模变小,这个过程中不能添加其它的过程,否则其它也会参与递归,这是应该十分警惕的。