zoukankan      html  css  js  c++  java
  • 【算法学习笔记】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
    ",al);
    	for(i=0;i<al;i++)
    		printf("%.2lf ",a[i]);
    	printf("
    ");
    	for(i=0;i<al;i++)
    		printf("%d ",b[i]);
    	printf("
    ");
    	for(i=0;i<cl;i++)
    		printf("%.2lf ",c[i]);
    	printf("
    ");
    
    }  

    此处为任务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,貌似也不超时。


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


  • 相关阅读:
    ELK相关操作记录-运维笔记
    php执行普通shell命令
    rsync 限速同步文件
    mysql 压测工具启动报 error while loading shared libraries: libmysqlclient.so.20解决办法
    php连接SQL server 数据库测试php脚本
    mysql 5.6.24 主从配置(增加从库)
    Mysqldump参数大全(参数来源于mysql5.5.19源码)
    Linux下mysql-5.6重置root密码
    WSDL文档深入分析
    随笔
  • 原文地址:https://www.cnblogs.com/yuchenlin/p/4379271.html
Copyright © 2011-2022 走看看