【算法学习笔记】03.白书练习题stat(排序入门:冒泡,桶)

原题:

输入一些学生的分数,哪个分数出现的次数最多?如果有多个并列,从小到大输出。

任务1,分数为不超过100的非负整数。(题眼。)

任务2,分数为不超过100.00的非负实数。保留两位小数(两位的处理)

依照惯例,先看看我的垃圾代码。

#include <stdio.h>
#include <string.h> 
#include <math.h> 
int b[100];
double a[100],c[100];
int main()
{	
	int i =0,flag,j,al,max=0,k=0,cl;
	double t;
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	memset(c,0,sizeof(c));
	while(scanf("%lf",&t)==1)
	{ 
		flag=0;
		for(j=0;j<i;j++)
		{
			if(fabs(a[j]-t)<=0.000000001)
			{	
				b[j]++; 
				flag =1; 
				if(b[j]>max)
				{
					max=b[j];
					memset(c,0,sizeof(c));
					k=0;
					c[k++]=a[j];
				}
				else if(b[j]==max)
				{
					c[k++]=a[j];
				}
				break;
			} 
		}
		if(!flag)
		{
			a[i]=t;
			b[i]=1;
			i++;
		}
	}
	al=i;//利用i来记录a的长度 不同数字的个数
	cl=k;//c的长度 最多出现的数字的个数

	//给c选择排序 
	for(i=0;i<cl;i++)
	{
		for(j=i;j<cl;j++)
		{
			if(c[i]>c[j])
			{
				t=c[j];
				c[j]=c[i];
				c[i]=t;
			}
		}
	}

	printf("%d\n",al);
	for(i=0;i<al;i++)
		printf("%.2lf ",a[i]);
	printf("\n");
	for(i=0;i<al;i++)
		printf("%d ",b[i]);
	printf("\n");
	for(i=0;i<cl;i++)
		printf("%.2lf ",c[i]);
	printf("\n");

}  

此处为任务2的代码,任务1直接将a,c换成int型数组即可。

此方法很弱智地绕弯型思维,竟然用了三个数组完成这件事,而且数组长度明显存在隐患。因为方法错误而产生了各种较为难以解决的问题。

此方法的思维模式是:

1.如何将输入的数字存起来,并且记录其出现的次数。

2.如何找到出现最多次的数字,并存起来。(此处需要动态重置数组)

3.如何排序

于是为了解决这三个问题,花费了非常复杂的代码。虽然见佛当佛见鬼杀鬼,但是在性能上明显输了。而且有缺点。

1.数组长度漏洞

2.doule型比较存在隐患

此时,再看看什么叫算法艺术。

        int max=0,n=0,a[100]={0},x;
	while(cin >> x)
	{
		if(++a[x]>max) max=a[x];
		if(x>n) n=x;//此处记录最大的分数,用来缩小循环次数
	}
	for(int i=0;i<=n;i++) 
               if(a[i]==max) cout << i << " ";

多么简洁,多么完美,多么像一个清新可人的少女阿我去。。。

启发

1.数组下标本身就是一个有序数组,因为0~100,正好是题目中要求的范围,

此举(1) 解决了一个记录输入数据的数组,节省空间。(2)解决了排序的问题,直接按序输出,即可。

2.此代码简洁异常。比如++的利用,比如a[100]={0}的利用,不过这个貌似是才c++的特殊用法。c里是memset()

3.这才是直接型的思维。 你本来要输入未知个数个数据,但是这个数据的范围是有限的,而且你还要在这些数据上做文章。

那么用数组下标来表示数据,用数组内容来表示个数,极其合适。顺便解决了排序的问题

4.扩展性好,比如看任务2的代码。

        int max=0,n=-1,a[10010]={0}; //is hash?
	double x;
	while(cin >> x){
		if(++a[(int)floor(x*100)]>max) max=a[(int)floor(x*100+0.5)];// +0.5防止浮点数陷阱
		if((int)floor(x*100)>n) n=(int)floor(x*100);//用来缩小循环次数
	}	
	for(int i=0;i<=n;i++) if(a[i]==max)
		printf("%.2lf ",(double)i/100);
		//cout << setiosflags(ios::fixed) << setprecision(2) << (double)i/100 << " ";

接4. 因为要解决有关二位小数的问题,但是数组下标只能是整数。所以不妨用10000来表示100.00 用2233来表示22.33

简直完美。

今天才知道这个叫做桶排序

今天拿冒泡排序的代码去试wikioi的排序题。。。超时太严重了

在题解中了解到了,归并排序,,快速排序,希尔排序,等等还有c++的stl中的sort,貌似也不超时。


选择排序,是一种不稳定的排序,冒泡排序是一种稳定排序。。。我之前一直弄混了。


你可能感兴趣的:(学习笔记)