常用排序算法的c++实现(冒泡,选择,插入,堆,shell,快速,归并 )与sort()对比

     偶然在书上看到句话,“为C++程序员所津津乐道的一件事,就是sort()全面打败c语言的quicksort”,于是决定亲自测试下,正好将其他的排序也一并测试了,当做当初没写的补偿吧。

     测试文件的一些说明:

    1、 测试中如果用数组,当MAX达到1000000时,会stack over,所以这里全部用了vector。

    2、随机数用一个全局vector保存,单独排序时直接vector v(orited),就这但来说c++确实很方便啊,因为有的递归调用,调用过程中vector为多大都不确定,用数组怎么初始化就成为了一个问题。

    3、测试排序的函数命名全部为下划线分割的方式,如select_sort()。

    4、排序结果经过写入文件验证。

    5、文件在win7,vs6,vs08,以及gcc下编译通过。vs08下,最初用的文件操作用FILE,会有错,可以加以修改为stream,比如打开和判空修改如下:

FILE *fp =fopen("data.txt","wr");
ofstream fp("data.txt");
if (fp==NULL)
if (fp.fail())
写入文件两个的对应部分,当然读出的时候 ip >> temp; v.push_back(temp);即可
fp << orited[i] << " ";//这里最好加上个空格,不然文件中连起来的数字也没意义
fprintf(fp,"%d ",orited[i]);
//关闭
//	fclose(fp);
	fp.close();


    最终修改的标准c++测试文件如下

//============================================================================
// Name        : sort.cpp
// Author      : xia
// Version     : 1.0
// Copyright   : NUAA
// Description : 各种排序算法的比较(冒泡,选择,快速,希尔,堆,归并以及algorithm的sort)
//============================================================================
#include 
#include 
#include 
#include 
#include 
using namespace std;

const int MAX = 1000;//当MAX为一百万,用数组会stack overflow,所以全部用vector
vector orited;//全局原始未排序vector

void randNum()
{//产生随机数存于vector
	ofstream fp("data.txt");
	if (fp.fail())
	{
		cout << "open data error " << endl;
		exit(EXIT_FAILURE);
	}
	srand((unsigned)time(NULL));
	for (int i=0 ; i &v ,int low ,int high)
{//对vector进行划分,返回枢轴下标
	int pivotkey;
	pivotkey = v[low] ;
	while ( low < high )
	{
		while (low < high && v[high] >= pivotkey)
			high -- ;
		v[low] = v[high];
		while (low < high && v[low] <= pivotkey )
			low ++ ;
		v[high] = v[low];	
	}
	v[low] = pivotkey ;
	return low ;
}
void quickSort(vector &number ,int left ,int right)
{//用引用解决传参问题,以下类似
	if ( left < right )
	{
		int i = Partion(number , left, right) ; 
		quickSort(number, left, i-1);   // 对左边进行递归 
		quickSort(number, i+1, right);  // 对右边进行递归 	
	}
}
void quick_sort()
{//快速排序测试程序
	double start ,end ;
	vector v(orited);//直接用全局orited初始化v
	start = clock() ;
	quickSort(v,0,MAX-1);
	end = clock();
	cout << "quick  sort cost : " << end - start << endl;
}
/************************************************************************/
/*      插入排序                                                        */
/************************************************************************/
void InsertSort(vector &v)
{ //对vector做插入排序
	int i,j;
	int key;
	for(i=1 ; i < v.size() ; i++)
		if ( v[i] < v[i-1] )// "<",将v[i]插入有序子表 
		{
			key = v[i]; 
			for( j=i-1 ; key < v[j] ; j-- )
				v[j+1] = v[j]; // 记录后移 
			v[j+1] = key; // 插入到正确位置 
		}
}
void insert_sort()
{
	vector v(orited);
	double start ,end;
	start = clock();
	InsertSort(v);
	end = clock();
	cout << "insert sort cost : " <<  end - start << endl;
}
/************************************************************************/
/*     algorithm的sort方法                                              */
/************************************************************************/
void vector_sort()
{
	double start ,end ;
	vector v(orited);
	start = clock();
	sort(v.begin(),v.end());
	end = clock();
	cout << "vector sort cost : " << end - start << endl;
}
/************************************************************************/
/*        冒泡排序                                                      */
/************************************************************************/
void bubble_sort()
{
	int i,j;
	vector v(orited);
	double start ,end;

	start = clock();
	for ( i=0 ; i< MAX ; i++)
	{
		for (j=i+1 ; j< MAX ; j++)
		{
			if (v[i] > v[j])//最小的往左冒泡
			{
				swap(v[i],v[j]);
			}
		}
	}
	end = clock();
	cout << "bubble sort cost : " <<  end - start << endl;
}
/************************************************************************/
/*      选择排序                                                        */
/************************************************************************/
void select_sort()
{
	int i,j,min;
	vector v(orited);
	double start ,end;
	start = clock();
	for (i=0 ; i< MAX ; i++)
	{
		min = i ;
		for (j=i+1 ; j &array,int start ,int mid ,int end)
{//合并vector的start-mid和mid-end两段
	int j,k,l;
	vector temp(array); //引入temp,方便用array作为汇总
	for( j=mid+1,k=start ; start<=mid&&j<=end ; k++ ) 
	{
		if ( temp[start] < temp[j] )
			array[k] = temp[start++];
		else
			array[k] = temp[j++];
	}
	if( start <= mid )
	{
		for( l=0 ; l <= mid-start ; l++)
			array[k+l] = temp[start+l]; //将剩余0至min-start的复制到array
	}
	if( j <= end )
	{
		for( l=0 ; l<=end-j ; l++ )
			array[k+l]= temp[j+l]; //复制j至end到array
	}
}
void MergeSort( vector &v, int low ,int high )
{
	if (low < high)
	{		
		int mid = ( low + high )/2; //平分
		MergeSort( v , low , mid ); //递归合并低段
		MergeSort( v , mid+1 , high ); //递归合并高段
		Merge( v , low , mid , high ) ; //合并排序后两段
	}
}
//归并排序的测试函数
void  merge_sort()
{
	vector v( orited );
	double start ,end;
	start = clock();
	MergeSort(v,0,MAX-1);
	end = clock();
	cout << "merge  sort cost : " <<  end - start << endl;
}
/************************************************************************/
/*      希尔排序                                                        */
/************************************************************************/
const int SORTCOUNT = 20;//希尔排序的排序次数
const int dlta[SORTCOUNT] = {2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3};//增量数组
void ShellInsert(vector &v , int dk)
{//对v做一趟shell插入排序,增量为dk,不是1;j<=0时,找到插入位置
	int i,j;
	for ( i=dk ; i < v.size() ; i++)
	{
		if (v[i] < v[i-dk])
		{
			int temp = v[i];//暂存
			for (j=i-dk ; j>0 && temp < v[j] ; j -= dk)
				v[j+dk] = v[j] ;//记录后移,查找插入位置 
			v[j+dk] = temp; //插入
		}
	}
}
void ShellSort(vector &v ,const int dlta[] ,int t)
{//希尔排序
	for (int k=0 ; k < t ; k++)
		ShellInsert(v,dlta[k]) ;//一趟增量为dlta[k]的插入排序
}
void shell_sort()
{
	vector v( orited );
	double start ,end;
	start = clock();
	ShellSort(v,dlta,SORTCOUNT);
	end = clock();
	cout << "shell  sort cost : " <<  end - start << endl;	
}
/************************************************************************/
/*       堆排序                                                         */
/************************************************************************/
void HeapAdjust(vector &v ,int s ,int m)//将堆用数组表示,此处为vector
{//调整为大顶堆
	int rc,j;
	rc = v[s];
	for ( j=2*s ; j<= m ; j *= 2 )
	{//沿key较大的孩子结点向下筛选
		if (j= v[j] )
			break;// rc应插入在位置s上 
		v[s] = v[j] ;
		s = j;
	}
	v[s] = rc ; //插入
}
void HeapSort(vector &v)
{ // 对vector进行堆排序
	int t , i;
	for( i=v.size()/2 ; i>0 ; i--) // 把v建成大顶堆
		HeapAdjust( v,i,v.size()-1 );
	for( i=v.size()-1 ; i>0 ; i-- )
	{//将堆顶记录和当前未经排序子序列[0..i]中最后一个记录相互交换
		t = v[0];
		v[0] = v[i];
		v[i] = t ;
		HeapAdjust(v,0,i-1); // 将v[0..i-1]重新调整为大顶堆 
	}
}
//堆排序测试函数
void heap_sort()
{
	vector v( orited );
	double start ,end;
	start = clock();
	HeapSort(v);
	end = clock();
	cout << "heap   sort cost : " <<  end - start << endl;	
}
int main(int argc, char* argv[])
{
	randNum();    //每次更新MAX,重新生成随机数,存到vector
 	vector_sort();
 	quick_sort(); 
 	bubble_sort();
  	select_sort();
 	merge_sort(); 
 	shell_sort(); 
 	heap_sort();  
	insert_sort();
	return 0;
}

       关于sort(),这里 默认是按照升序排列的,如果想按照降序排列,可添加函数:

bool compare(int a ,int b)
{
	return a>b;//a>b降序 a
并调用时
	sort(v.begin(),v.end(),compare);
       即可。

       在程序的main部分给出了部分测试结果,其中shell的不具有太大参考性,于是没列(用书的原话说,shell排序的分析是一个复杂的问题,因为时间是所取增量序列的函数,这涉及一些数学上尚未解决的问题),将排序结果保存在文件中观看,可以看到,shell的结果,不像快速排序似的能完全正确,概率问题。

     vc6测试结果如下:

 

Sort()

Quick

Bubble

Select

Merge

Shell

heap

insert

1k

0

1

78

35

107

14

2

21

1w

2

12

4883

3099

7947

1135

34

2274

10w

26

142

410630

385299

774607

108289

267

220359



vs08下测试结果如下:(vs08 下,insert会有部分错误,所以未列出)

 

Sort()

Quick

Bubble

Select

Merge

Shell

heap

1k

26

2

193

291

15

90

8

1w

302

29

12674

8203

216

3010

57

10w

3624

378

1.02754e+006

804142

804142

804142

713


gcc下测试结果:

 

Sort()

Quick

Bubble

Select

Merge

Shell

heap

insert

1k

0

0

9

3

1

2

1

2

1w

2

3

725

452

81

170

4

294

10w

29

27

55812

34269

4390

16272

45

28208


       统计结果当然是明显的,除了在vs08中,sort()的确不是一般的快啊(尤其是vc6下,压倒性优势),紧跟其后的是quicksort和heapsort。对于heapsort,这里的堆,直接用顺序表示了,也算省了不少时间。


      神奇的是vc6下的merge居然比冒泡还慢,没天理嘛,当然还好gcc这样一个标准的c++测试给了我们信心。

      刚统计完发现插入没做,补充上统计结果, 目前就算是这样吧,有什么不对的,请跟帖说明修改啊。


     后记:后来改用了双向冒泡,发现比原冒泡快了一倍多,比选择还略快(后来测试,起初的写法出错了,其实和单向冒泡速度是一样的)

代码如下:

	for (i=0 ; i< MAX ; i++)
	{
		k = MAX-i-1;
		for (j=i+1 ; j< k ; j++)//改用双向冒泡
		{
			if (v[j] < v[i])
			{
				swap(&v[i],&v[j]);
			}
			if (v[MAX-j-1] > v[k])
			{
				swap(v[MAX-j-1],v[k]);
			}
		}
	}


运行时间结果马上更新

       本想把选择改为双向选择,min存低位,max存在高位,第二个循环j

你可能感兴趣的:(c/c++进行时)