C语言课程实验9

第九次实验

(1)Python中的random模块提供了丰富的随机数相关函数,现要求用C语言仿照random模块实现一个函数库,其中应包括以下函数。

  • random(): 产生一个[0, 1)的随机浮点数。
  • uniform(a, b),用于生成一个指定范围内的随机浮点数,两个参数a和b:一个是上限,一个是下限。如果a>b,则生成的随机数n满足:b<=n<=a;如果a<b,则a<=n<=b。
  • randint(a, b),用于生成一个指定范围内的整数。其中参数a是下限,参数b是上限,生成的随机数n满足:a<=n<=b。
  • randrange(start, stop, step),从指定范围[start,stop]内按指定步长stop递增的集合中,获取一个随机数。例如,randrange(10, 100, 2),结果相当于从{10,12,14,16,…,96,98}集合中获取一个随机数。

要求:函数组织在两个文件myrandom.h和myrandom.c中,其中,myrandom.h包含上述函数的声明,myrandom.c包含上述函数的定义(实现);main()函数在文件source.c中;要对每个函数进行测试。这3个文件要放在一个工程中才能正确编译运行。

思路

利用C语言随机数生成函数完成

代码

// myrandom.h
#pragma once

double random();

double uniform(int a, int b); 

int randint(int a, int b);

int randrange(int start, int stop, int step);
// myrandom.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include "myrandom.h"

double random()
{
    double r = (double)rand() / (RAND_MAX + 1.0);
    return r;
}

double uniform(int a, int b)
{
    double r = 0;
    if (a < b)
        r = random() * b + a;
    else
        r = random() * a + b;
    return r;
}

int randint(int a, int b)
{
    return (rand() % (b - a)) + a;
}

int randrange(int start, int stop, int step)
{
    int arr[10001] = { 0 };
    int len = 0;
    while (len < (stop - start) / step)
    {
        arr[len] = start + step * len;
        ++len;
    }
    for (int i = 0; i < len; ++i)
        printf("%d ", arr[i]);
    int randLoc = rand() % len;
    return arr[randLoc];
}
// main.c
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include "myrandom.h"

int main()
{
    srand((unsigned int)time(NULL));
    //printf("%lf",random());
	//printf("%lf",uniform(1,10));
	//printf("%d",randint(1,10));
	//printf("%d",randrange(1,100,2));  
	return EXIT_SUCCESS;
}

(2)编写一个简单的猜数游戏,程序产生一个1-100的随机数,用户猜这个数,程序会给出“高了”或者“低了”的提示,直到用户猜对或者放弃(假定用户输入-1表示放弃)。如果用户最终猜对了,且猜的次数在5次以下,则输出“Good!”;猜的次数在5~8次,则输出“Not Bad!”;否则输出“You can do better!”。

思路

  1. 产生随机数;
  2. 输入猜测数,计数次数加一;
  3. 如果猜错,返回第2步;如果猜对,按要求输出并退出程序;如果放弃直接退出;

代码

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>

int judge(int input, int randNum, int times)
{
    int flag = 0;
    if (input < randNum) printf("低了\n");
    else if (input > randNum) printf("高了\n");
    else
    {
        //printf("猜中了,共猜了%d次", times);
        if (times < 5)
            printf("Good\n");
        else if (times < 8)
            printf("Not Bad\n");
        else
            printf("You can do better\n");
        flag = 1;
    }
    return flag;
}

void guessMain()
{
    int randNum = rand() % 100;
    int times = 0,
        input = 0;
    while (1)
    {
        printf("Please input a num(-1 for exit):\n");
        scanf("%d", &input);
        if (input == -1) break;
        ++times;

        if (judge(input, randNum, times))
            break;
    }
}

int main()
{
    guessMain();

	return EXIT_SUCCESS;
}

(3)写一个递归程序,计算:
C ( m , n ) = C m n = { 1 当 n = 0 m 当 n = 1 C m m − n 当 m < 2 n C m − 1 n − 1 + C m − 1 n 当 m ≥ 2 n C(m,n)=C_m^n= \begin{cases} 1&当n=0\\ m&当n=1\\ C_m^{m-n}&当m<2n\\ C_{m-1}^{n-1}+C_{m-1}^n&当m\ge2n \end{cases} C(m,n)=Cmn=1mCmmnCm1n1+Cm1nn=0n=1m<2nm2n
递归逻辑比较简单,直接贴代码

int recur(int m, int n)
{
    if (n == 0) return 1;
    if (n == 1) return m;
    if (m < 2 * n) return recur(m, m - n);
    else return recur(m - 1, n) + recur(m - 1, n - 1);
}

(4)写一个递归程序,计算一个算术表达式的值,其中只有+运算符。例如,5+3+9+1。要求首先描述问题的递归特征,即将问题分解为至少两部分,其中一部分可以直接解决,其他部分可以基于子问题的解来解决。

思路

此题只有加法运算,因此运算顺序不影响结果,本次采用从右往左运算进行递归。

递归特征描述为:
F ( m , n ) = { 第 n 位 数 当 m = n 第 m 位 数 + F ( m + 1 , n ) 当 m < n F(m,n)= \begin{cases} 第n位数&当m=n\\ 第m位数+F(m+1,n)&当m<n \end{cases} F(m,n)={nm+F(m+1,n)m=nm<n
F(m,n)表示从第m位数到第n位数之间的表达式的值

代码

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>

#define N 100

void input(char exprs[], int &e_len, int n[], int &n_len)
{
	printf("请输入加法表达式(=结尾):\n");
	char ch;
	// 处理一位数输入
	int i = 0;
	int j = 0;
	while ((ch = getchar()) != '=')
	{
		if ('0' <= ch && ch <= '9')
			n[i++] = ch - '0';
		else
			exprs[j++] = ch;
	}
	e_len = j;
	n_len = i;
}



int compute(int a, char expr, int b)
{
	int ans = 0;
	switch (expr)
	{
	case '+':
		ans = a + b;
		break;
	case '-':
		ans = a - b;
		break;
	}
	return ans;
}

int accumulate(int n[], int n_len, int pos)
{
	if (n_len == pos + 1) return n[pos];
	return compute(n[pos], '+', accumulate(n, n_len, pos + 1));
}

int main()
{
	char exprs[N] = { '\0' };
	int n[N] = { 0 };
	int expr_len = 0,
		n_len = 0;
	input(exprs, expr_len, n, n_len);

	int ans = accumulate(n, n_len, 0);

	printf("%d", ans);
	return EXIT_SUCCESS;
}

PS:本程序处理输入时未考虑多位数,因此只能进行一位数的加法运算,需要多位数加法还请自行实现多位数输入处理,算法逻辑无需修改。

(5)写一个递归程序,计算一个算术表达式的值,其中有+和-两种运算符。例如,5-3-9+1。同样,首先描述问题的递归特征。

思路

此题有加法减法两种运算,因此只能按照表达式运算顺序从左到右运算。

递归特征:
F ( m , c h ( m , n ) , n ) = { 第 m 位 数 当 m = n F ( m , c h ( m , n − 1 ) , n − 1 ) + 第 n 位 数 当 m ≤ n F(m,ch(m,n),n)= \begin{cases} 第m位数&当m=n\\ F(m,ch(m,n-1),n-1)+第n位数&当m\le n \end{cases} F(m,ch(m,n),n)={mF(m,ch(m,n1),n1)+nm=nmn
F(m,ch(m,n),n)表示从第m个数到第n个数的表达式的值,ch(m,n)表示之间的运算符。

代码

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>


#define N 100

void input(char exprs[], int* e_len, int n[], int* n_len)
{
	printf("请输入加法表达式(=结尾):\n");
	char ch;
	// 处理一位数输入
	int i = 0;
	int j = 0;
	while ((ch = getchar()) != '=')
	{
		if ('0' <= ch && ch <= '9')
			n[i++] = ch - '0';
		else
			exprs[j++] = ch;
	}
	*e_len = j;
	*n_len = i;
}



int compute(int a, char expr, int b)
{
	int ans = 0;
	switch (expr)
	{
	case '+':
		ans = a + b;
		break;
	case '-':
		ans = a - b;
		break;
	}
	return ans;
}

int accumulate(int n[], int n_len, char exprs[])
{
	if (0 == n_len-1) return n[n_len-1];
	return compute(accumulate(n, n_len-1, exprs), exprs[n_len - 2], n[n_len - 1]);
}

int main()
{
	char exprs[N] = { '\0' };
	int n[N] = { 0 };
	int expr_len = 0,
		n_len = 0;
	input(exprs, &expr_len, n, &n_len);

	int ans = accumulate(n, n_len, exprs);

	printf("%d", ans);
	return EXIT_SUCCESS;
}

PS:本程序处理输入时未考虑多位数,因此只能进行一位数的加法运算,需要多位数加法还请自行实现多位数输入处理,算法逻辑无需修改。

(6)写一个递归程序,输出1~n个自然数中任意取k个数字的所有组合。程序运行时输入n和k的值。例如,如果输入n=5,k=3,则输出:123,124,125,134,135,145等组合。要求首先描述问题的递归特征。每个组合数可以以一个整数的形式输出,但顺序不重要,例如,123,132,231等被认为是同一个组合。

思路

同一个组合只输出一次。

递归特征:

全排列特征
F ( m , n , k ) = F ( m , n , 1 ) , F ( m , n , k − 1 ) F ( m , n , 1 ) 和 F ( m + 1 , n , k − 1 ) 不 存 在 同 样 的 数 F(m,n,k)=F(m,n,1),F(m,n,k-1)\\ F(m,n,1)和F(m+1,n,k-1)不存在同样的数 F(m,n,k)=F(m,n,1),F(m,n,k1)F(m,n,1)F(m+1,n,k1)
组合特征(本题)
F ( m , n , k ) = m , F ( m + 1 , n , k − 1 )                   s . t . m ≤ n F(m,n,k)=m,F(m+1,n,k-1)\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space s.t.m\le n F(m,n,k)=m,F(m+1,n,k1)                 s.t.mn
F(m,n,k)表示从m到n之前取k位数的组合

代码

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>

#define N 101

void recur(int arr[],int len, int m, int n, int k)
{
	for (int i = m; i <= n+1; ++i)
	{
		if (k == 0)
		{
			//printf("当前%d个元素\t", len);
			for (int j = 0; j < len; ++j)
				printf("%d", arr[j]);
			printf("\n");
			break;
		}
		arr[len] = i;
		recur(arr, len+1, i+1, n, k - 1);
	}

}

int main()
{
	//recur(1, 5, 3);
	int arr[N] = { 0 },
		n = 0,
		k = 0;
	//n = 5; k = 3;
	scanf("%d,%d", &n, &k);

	recur(arr, 0, 1, n, k);
	return EXIT_SUCCESS;
}

结语

  1. 代码仅对思路作出实现,效率比较低下,代码质量较差,还请谅解。
  2. 若以上思路或程序有误,还请不吝赐教。
  3. 如果您有改进意见,欢迎指出。
  4. 程序的相关问题都欢迎交流
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值