The algorithm⑤:analog computation① (Review) C++ & C

模拟计算问题

基础知识

现实中的问题虽然各式各样,但在很多情况下,我们都可以发现它们都是有规律的从而得到解题的运算公式,这样就可以编程加以解决

并非都是这样,也有些问题是很难找到统一的公式来解决
对于这类问题,我们在求解时一般是按照问题描述的步骤,一步步执行下去,执行到最后就能得到答案
(ps:张 称之为 “它让你还干啥你干啥”,就是“模拟”)

这样的问题,在规模很小的情况下,手工计算即可,但是规模增加到一定程度时,手工计算就很吃力了,这时候采用编程模拟手工解决该问题的步骤,一次次执行,从而得到问题的解,对于这类问题我们称之为“模拟题”。

在计算机专业中最为经典模拟问题应该是约瑟夫问题了。

模拟题一般都是些相对简单的题目,对于编程初学者可以说是练习编程能力的题目(???为啥xiao没感觉简单?汗,可能是现在还太,,,小白了叭),它基本上不会涉及到太难的算法,这种题也不考虑太多的细节

不过,有些模拟题的步骤比较繁琐模拟起来也很麻烦,需要编程者考虑到各种可能存在的情况

练习:

接下来,我们来练习几道“模拟题”:

①7001 中位数
(来源:poj.org 2623)
题目描述
输入、输出
样例

解题分析:

这是一道简单的模拟题按照题目要求来求解即可
题目中已经给出序列的中位数的定义
如果有奇数个元素,中位数为排序后的中间元素值;如果有偶数个元素,中位数为排序后,中间两个数的平均值。
因此求解本题首先需要对序列进行排序,然后判断是否是奇数个还是偶数个,最后再求中位数

三步:
①:给读入序列排序;
②:判断当前序列中所包含个数是奇数个还是偶数个;
③:根据奇数或偶数个如题所述方法来计算中位数即可;

#include <stdio.h>
#include <stdlib.h>
#define LL long long //我们定义了一个符号常量
LL que[250001];  //定义了一个que的这样一个数组
int cmp(const void *a,const void *b){
return *(int *)a-*(int *)b;
}


int main(){
    int i,n;
    double res=0.0;
    scanf("%d",&n);
    for(i=0;i<n;i++){
        scanf("%lld",&que[i]);
    }
    qsort(que,n,sizeof(que[0]),cmp);
    if(n%2==1)res=que[n/2];
    else res=(que[n/2]+que[n/2-1])*0.5;
    printf("%.1f\n",res);
    return 0;
}

思考:

①:上述代码中我们定义了一个 que 数组是用来干嘛的?
用来 存储读入的数字的,也就是说,存储所给的数列的,因为题上说的是所给序列范围是大于0,小于25w的,所以咱们代码中给的是250001,所以咱们这里面肯定不会出现数组越界的问题

LL que[250001];  //定义了一个que的这样一个数组

②:第二个让大家思考的就是咱们的排序板块了,可能有的同学不太理解这块,但是,大家看一下,咱们至少可以知道这块是在干什么,咱们定义了一个什么?
定义了一个函数,这个函数是一个整型的,函数名称是 cmp

int cmp(const void *a,const void *b){
return *(int *)a-*(int *)b;
}

③:那咱们接下来再看,②中定义的这个函数,它要被用在哪里,大家先别看别的,先在main函数中找 对cmp函数定义的这块是在哪里。咱们现在就来找一下,在main函数中,哪块是用到了对cmp函数的调用,咱们一行一行看,就看到了。

是在

qsort(que,n,sizeof(que[0]),cmp);

在qsort这个函数这里

④:那么qsort这明显又是一个函数,那么此时,咱们会看到,qsort这个函数里面有四个参数,其中这个 cmp 这个函数作为了qsort函数的第四个参数出现了。
那么反过来qsort这个函数它的作用是什么?
它就是用来实现排序的。

⑤:那么既然我想让qsort直接来完成对,咱们看,que是把所给出来的这些数字都存在这个que数组当中的,所以此时,要对此数组中的所有输入元素排序,用到的是qsort,那既然想用qsort,就还要有一个前提,这个qsort这个函数,是包含在 stdlib.h 这个头文件当中的,所以咱们在前面写头文件的时候,要把 stdlib 头文件给写出来。

#include <stdlib.h>

⑥:然后接下来咱们看,要搞清楚qsort里面这四个参数的意义

1.第一个参数,就是咱们待排序数的首地址,对,咱们要给他一个地址,因为咱们把它放到数组中了,所以数组名,就是它的首地址,因此此时咱们这块的第一个参数就写数组名就行了。

2.第二个参数,就是待排序数的个数,咱们这个n是前面本身就给出来的,所以n就是要排序的个数,因为,它这些数,放在了一个数组当中,数组呢,开辟的是一段连续的存储单元,那么,咱们仅仅给出首地址了,那其他数放在了什么位置,咱们通过什么,通过首地址和当前每个数据元素所占用的字节空间就能够计算出来,那么,每个数据元素在这个数组中是占两个字节,四个字节还是占八个字节呢,我们说,良好的程序设计是不需要用立即数来表示的,咱们用什么呢?用sizeof ,那么相当于,咱们可以知道了就是对于当前数组元素中每一个数据元素,它所占的字节数是多少,然后有了首地址,那相当于咱们可以知道,每一个数据元素它所存放的位置。

3.最后的参数呢,就是 cmp 。

⑧:那么大家都看到了 qsort 这个函数, qsort 这个函数明明是用来做排序的,那么大家在前三个参数里面,咱们仅仅看到的是,我将对哪些数排序,那么它需要依据的排序规则是什么样的,在前三个参数中是根本就看不到的。

那么,给qsort提供了排序依据或者说排序准则的是哪个参数呢,显然就是我们最后面的这个cmp的这个函数


⑨:那cmp是怎么排的呢?

我们回过头来看一下上面这部分对cmp的这个定义。
cmp呢,cmp函数定义的这个头都是这样的,就是固定的写法。
即要定义两个 const ,这个常量的 void ,空类型的指针,一个是 a ,一个是 b ,然后,我要对整型数进行排序,所以,

int cmp(const void *a,const void *b){
return *(int *)a-*(int *)b;
}

这块里面,把空类型转换成整型,它有一个强制类型转换,看到了吗?上面的,那这两个括号里转换的显示都是 int ,代表的咱们就是对于整型数进行排序,那么其实在这个括号里面所有的数据类型都行,比如说我还可以对 字符 来进行排序,那这个 int 的地方 ,咱们就把它变成 char ;如果要是对浮点型进行排序,咱们就把这块可以变成 float 。

然后呢,我们看到,a 是我们当前定义的第一个形参, b 是第二个形参,那么 return 后面的 a - b 代表的是 从小到大排序 。如果咱们把它变成 b - a ,那么就是从大到小排序了。

这样大家理解了吗?


那我们理解了 cmp 函数之后呢,其实咱们上面已经说过, res 就是咱们要留存最终的这个结果的,然后 scanf 是来读入一共有多少个数,要用来做排序,并求中位数的。

然后接下来的循环,是咱们读入每一个数字,然后把它放在了 que 的数组当中 。

之后呢,接下来代码对 que 这个数组当中的所有数据来进行排序,这个咱们刚刚讲了,最后咱们就看 n 是奇数 还是 偶数 ,从而对它采用对应的办法来进行算中位数。

那咱们要怎么做呢?

    if(n%2==1)res=que[n/2];

如果它是奇数的话,那中位数就是中间位的那个数,所以,res的中位数,就是当前数组中,处于 n/2 那个位置的数。

    else res=(que[n/2]+que[n/2-1])*0.5;

否则它要是偶数的话呢?
那就是 n/2 和 n/2-1 这个位置的数相加再去除以 2 ,或者是乘以 0.5 。

那么咱们看一下上述两个判断这块,以及上面题目中人家说的,(题目中关于中位数算法的说法,偶数部分说的是 n/2 和 n/2+1处的平均值),大家看,而我们代码中却写的是 n/2 ,和 n/2-1 ,现在问一下,是咱们的程序写错了吗?为什么?

因为题目中明确指出,输入次序是从1开始的,而我们当前的数组,咱们 que 数组的数组下标是从0开始的,所以实际上是,咱们这个 n/2 实际上是 n/2+1 这个数,而 n/2-1 就是我们前面所说的 n/2 这个数,这点一定要注意啦,不然完全瞎照题目写的话,提交上去就是 WA .

其他的,就没什么了ba,求出来以后,咱们 一位小数保留 ,输出就可以啦~


因为大家可能是头一次接触到 qsort 函数以及它的这种要对 cmp 的这种定义,( 捂脸)行叭,是因为xiao是第一次接触到hahaha ),所以咱们这块分析的稍微多一点,不过大家可以捡主要得看嘛hhh

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值