冒泡排序法,选择排序法,归并排序法比较.

对于c语言初学者来说第一个接触的排序方法一般是冒泡排序法.

冒泡排序法是通过设置双层循环嵌套来比较相邻的两个元素.

	for(j=1; j<=n; j++)//冒泡法排序.
					for(i=1; i<=n-j; i++) {
						if(a[i]>a[i+1]) {
							t=a[i];
							a[i]=a[i+1];
							a[i+1]=t;
						}
					}

 而同样是通过设置双层循环嵌套的选择排序法则是将数组分为两段,一段为已排序列,另一端为未排序列,每次循环将未排序列中的第一个元素与剩下的所有元素比较,然后将目标元素放入已排序列中,直至整个数组为已排序列.

for(i=1; i<n; i++) {//选择排序法,和冒泡法不同的是,冒泡法是相邻的两数比较
					int k=i;//而选择排序法是未排序区域的第一个数与剩下的所有数比较.
					for(j=i+1; j<=n; j++) {
						if(a[j]<a[k])
							k=j;
						t=a[k];
						a[k]=a[i];
						a[i]=t;
					}
				}

(该图片引自百度百科.)

冒泡排序法与选择排序法相比较.

一.冒泡排序法.

 优点:比较简单,空间复杂度较低,是稳定的;                 

 缺点:时间复杂度太高,效率慢.

二.选择排序法.

优点:一轮比较只需要换一次位置;

缺点:效率慢,不稳定,排序过程中原序列会遭到破坏.(举个例子5,8,5,2,9   我们知道第一遍选择第一个元素5会和2交换,那么原序列中2个5的相对位置前后顺序就破坏了)

递归排序法.

void mergesort(int *num, int start, int end) {//归并排序
	int middle;//利用递归,先分再治.
	if(start<end) {//当未拆分为单个的时候利用递归继续拆分.
		middle= (start+end)/2;
		mergesort (num, start, middle) ;
		mergesort (num, middle+1, end) ;
		merge (num, start, middle, end);//治--合并排序
	}
}
void merge(int *num, int start, int middle, int end) {
	int n1=middle-start+1;
	int n2=end-middle;
	/*	int *L=new int[n1+1];
		int *R=new int[n2+1];*/
	int L[n1+1] ;//动态分配内存,声明两个数组容纳左右两边的数组
	int R[n2+1] ;
	int i, j=0, k;
	for (i=0; i<n1; i++) {//将新建的两个数组赋值
		*(L+i)=* (num+start+i) ;
	}
	*(L+n1)=1000000;
	for (i=0; i<n2; i++)
		* (R+i)=* (num+middle+i+1);
	* (R+n2) =1000000;
	i=0;
	for (k=start; k<=end; k++) {//进行合并.
		if(L[i]<=R[j]) {
			num[k]=L[i];
			i++;
		} else {
			num[k]=R[j];
			j++;
		}
	}
}

 具体思想如下图:

 (图片来自:图解排序算法(四)之归并排序 - dreamcatcher-cx - 博客园 (cnblogs.com),侵权联删.)

归并排序法就是利用递归思想将原数组一步一步拆分为更小的数组,然后对其合并排序.

归并排序是种稳定排序,能利用完全二叉树特性进行排序是一种高效的排序方法,归并排序的最好,最坏,平均时间复杂度均为O(nlogn)。

三种排序方法实际时间比较测试.

生成5000个随机整数以便于三种排序方法的测试.

一.冒泡排序法.

二.选择排序法.

三.归并排序法.

小结:经过多次尝试可得出结论相较于冒泡排序法和选择排序法来说,归并排序法能够明显减少排序时间,并且就稳定性来说归并排序法也是优于冒泡排序法的.

(另附比较三种排序方法效率的程序的代码.)

#include <stdlib.h>
#include <iostream>
#include <time.h>
using namespace std;
void mergesort(int *num, int start, int end) ;//函数的声明.
void merge(int *num, int start, int middle, int end) ;
//如果不先声明的话,当调用该
//函数时,编译器发现一个不认识的函数调用,不知道该函数的返回类型,就假设为int类型,
//等后面编译的时候编译器看到实际的函数,它认为有两个同名的函数,一个是文件中的函数
//,一个是编译器假设返回int的那个。为了防止编译器假设函数的返回类型,
//你可以显式地告诉它。告诉编译器函数会返回什么类型的语句就叫函数声明。
void mergesort(int *num, int start, int end) {//归并排序
	int middle;//利用递归,先分再治.
	if(start<end) {//当未拆分为单个的时候利用递归继续拆分.
		middle= (start+end)/2;
		mergesort (num, start, middle) ;
		mergesort (num, middle+1, end) ;
		merge (num, start, middle, end);//治--合并排序
	}
}
void merge(int *num, int start, int middle, int end) {
	int n1=middle-start+1;
	int n2=end-middle;
	/*	int *L=new int[n1+1];
		int *R=new int[n2+1];*/
	int L[n1+1] ;//动态分配内存,声明两个数组容纳左右两边的数组
	int R[n2+1] ;
	int i, j=0, k;
	for (i=0; i<n1; i++) {//将新建的两个数组赋值
		*(L+i)=* (num+start+i) ;
	}
	*(L+n1)=1000000;
	for (i=0; i<n2; i++)
		* (R+i)=* (num+middle+i+1);
	* (R+n2) =1000000;
	i=0;
	for (k=start; k<=end; k++) {//进行合并.
		if(L[i]<=R[j]) {
			num[k]=L[i];
			i++;
		} else {
			num[k]=R[j];
			j++;
		}
	}
}
int main() {
	while(1) {
		clock_t start,finish;
		double duration;
		int n,i,j,t,b;
		float tim;
		int a[100000];
		cout<<"输入个数(100000以内)"<<endl;
		cin>>n;
		srand (time(0));
		for(i=1; i<=n; i++) {
			a[i]=rand();
		}
		cout<<"产生的随机数:"<<endl;
		for(j=1; j<=n; j++) {
			cout<<a[j]<<"\t";
		}
		cout<<endl;
		/*	for(j=1; j<=n; j++)
				cout<<a[j]<<"\t";
			cout<<endl;*/

		cout<<" ****选择****" <<endl;
		cout<<" (1)冒泡排序"<<endl;
		cout<<" (2)选择排序"<<endl;
		cout<<" (3)归并排序"<<endl ;
		cout<<" (4)退出"<<endl;
		cin>>b;
		if(b==4)
			break;
		switch(b) {
			case 1: {
				start = clock() ;
				for(j=1; j<=n; j++)//冒泡法排序.
					for(i=1; i<=n-j; i++) {
						if(a[i]>a[i+1]) {
							t=a[i];
							a[i]=a[i+1];
							a[i+1]=t;
						}
					}
				cout<<"冒泡排序结果"<<endl;
				for(j=1; j<=n; j++)
					cout<<a[j]<<"\t";
				cout<<endl;
				finish = clock();
				tim= (double)(finish - start) / CLOCKS_PER_SEC;
				cout<<"用时:"<<endl<<tim<<endl;
			}
			break;
			case 2: {
				start = clock() ;
				for(i=1; i<n; i++) {//选择排序法,和冒泡法不同的是,冒泡法是相邻的两数比较
					int k=i;//而选择排序法是未排序区域的第一个数与剩下的所有数比较.
					for(j=i+1; j<=n; j++) {
						if(a[j]<a[k])
							k=j;
						t=a[k];
						a[k]=a[i];
						a[i]=t;
					}
				}
				cout<<"选择排序结果"<<endl;
				for(j=1; j<=n; j++)
					cout<<a[j]<<"\t";
				cout<<endl;
				finish = clock() ;
				tim = (double) (finish - start) / CLOCKS_PER_SEC;
				cout<<"用时:"<<endl<<tim<<endl;
			}
			break;
			case 3: {
				start = clock() ;
				mergesort (a,0,n) ;//利用递归处理
				cout<<"归并排序结果"<<endl;
				for (i=1; i<=n; i++)
					cout<<a[i]<<"\t";
				cout<<endl;
				finish = clock() ;
				tim = (double) (finish-start)/CLOCKS_PER_SEC;
				cout<<"用时:"<<endl<<tim<<endl;
			}
			break;
		}
	}
	return 0;
}

posted @   冷月半明  阅读(95)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示