(欧) 第8章 循环、递归与概率

一个过程或函数直接调用自己本身或通过其他的过程或函数调用语句间接调用自己的过程或函数,称为递归过程或函数。


1、递归函数用来实现统计字符串中第一个空字符前面字符长度。举例来说:

char buf[]={'a','b','c','d','e','f','\0','x','y','z'};

字符串buf,当输入N=10或20,期待输出为6;当输入N=3或5,期待输出结果是3或5.

int mystrlen(char *buf,int N) {
	return mystrlen(buf,N/2)+mystrlen(buf,N/2,N/2);
}

注意:没有递归退出条件。

int mystrlen(char *buf,int N) {
	if(buf[0]==0 || N==0)
		return 0;
	else if(N==1)
		return 1;
	int t=mystrlen(buf,N/2);//折半递归取长度 
	if(t<N/2)//如果长度小于输入N值的一半,取当前长度 
		return t;
	else//反之取下面下面一个字符并继续递归 
		return mystrlen(buf,N/2)+mystrlen(buf,N/2,N/2);
}


2 从左上角A点到达右下角B点的路径,从起点出发后只能→或者↓,任何箭头都将增加路径长度。 


在不存在阻碍情况下,假设在任意M,N的此种格子上,从左上A出发到右下B的不同走法有f(M,N)种,则根据递推可知f(M,N)=f(M-1,N)+f(M,N-1),等号右边两项分别对应在当前点向下走一步和向右走一步的情况。递归终止情况为:

f(M,0)==f(0,N)==0  或者 f(1,1)==1


对于题目中有阻碍的情况,如下:

从A出发到X点的不同走法为f(4,2),到达X点后只有1种走法,即一直向右到B。

从A出发到Y点后不同走法为f(2,4),到达后再到B点的不同走法为f(3,2),因此连接的总数为f(2,4)*f(3,2)

至此,唯一没有涵盖的走法为Z点到B点,此种走法有且只有1种。

所以:17种。


典型递归问题

1、 f(0)=0,f(1)=1,f(n)=f(n-1)+f(n-2),求 f(1025) mod 5为多少?

分析:f(5n)=f(5n-1)+f(5n-2)= 2f(5n-2)+f(5n-3)=3f(5n-3)+2f(5n-4)=5f(5n-4)+3f(5n-5)

所以f(1025) mod 5 = 3f(1020) mod 5

依次类推:

f(1020) mod 5 = 3* f(1015) mod 5

.......

f(10) mod 5 = 3*f(5) mod 5

f(5) =5 ,所以mod后的值为0,所以 f(1025) mod 5 =0.


2 、设计递归算法,x(x(8))需要调用几次函数x(int n).

class Program
{
	static void main(string[] args) {
		int i;
		i=x(x(8));
	}
	static int x(int n) {
		if(n<=3)
			return 1;
		else
			return x(n-2)+x(n-4)+1;
	}
}
分析:单计算x(x(8))的值为9.但是本题考察的是调用了几次x函数。可以把x(8)理解成一个二叉树。树的结点个数就是调用次数。

8

6 4

    4     2      2    0

3    1
x(8)的结果为9,也就是调用了9次函数。所以一共调用的次数是18次。


循环与数组问题

1、求出下列输出结果

int x=10;
int y=10,i;
for(i=0;x>8;y=i++)
{
	printf("%d,%d",x--,y);
}
输出结果是:10 10 9 0.


int x=10;
int y=10,i;
for(i=0;x>8;)
{
	y=i++;
	printf("%d,%d",x--,y);
}
输出结果是:10 0 9 1.


2 、有两个等长数组A、B,所含元素相同,但顺序不同,只能取得A数组某值和B数组某值进行比较,比较结果为大于,小于或等于,但是不能取得同一数组A或B的两个数进行比较,也不能取得某数组中的某个值。写一个算法实现正确匹配。

分析:循环加判断可以解决这个问题。算法分析,假设两个数组A[10]、B[10]。将A.0和B.0进行比较,判断它们是否等值或大于、小于,如果等值则打印出来,不等则比较B.1 ………以此类推。

#include<iostream>
using namespace std;
void matching(int a[],int b[], int k) {
	int i=0;
	while(i<=k-1) {
		int j=0;
		while(j<=k-1) {
			if(a[i] == b[j]) {
				cout<<"a["<<i<<"]"<<"match"<<"b["<<j<<"]"<<endl;
				break;
			}
			j++;
		}
		i++;
	}
	cout<<endl;
}

int main() {
	int a[10]={1,2,3,4,5,6,7,8,9,10};
	int b[10]={10,6,4,5,1,8,7,9,3,2};
	int k=sizeof(a)/sizeof(int);
	matching(a,b,k);
	return 0;
}


3 用C++代码实现统计每个ASCII码字符的出现次数,最后给出出现次数。 对下列程序改错:

#include<iostream>
#include<cstdlib> 
using namespace std;
void histogram(char *src) {
	int i;
	char hist[256];
	for(i=0;i<256;i++) {
		hist[i]=0;
	}
	while(*src !='\0') {
		hist[*src]++;//这行应该改成hist[*src++]++,因为在while中循环体是看*src的值是否为'\0'来作为结束的。所以src必须递加。否则进入死循环
	} 
	
	for(i=0;i<=256;i++) {//此处应该改成i<256,否则越界
		printf("%d ",hist[i]);
	}
}


int main() {
	char *src="aaaabcdefghilklmnopqrst1234567890";
	histogram(src);
	return 0;
}


4 设计一个定时器程序,当输入一个时间,就按照输入值停留多少?

分析:可以用sleep来控制时间,并用双精度传值作参数传递。

#include<window.h>
#include<iostream>
using namespace std;
void timer(double x) {
	double cnt=0;
	cnt= x*1000;
	Sleep(cnt);//停留x*1000微秒 
}

int main() {
	timer(0.5);
	cout<<"0.5秒过去了"<<endl;
	timer(2*60);
	cout<<"2秒过去了"<<endl;
	timer(60*60);
	cout<<"1个小时过去了"<<endl; 
	return 0; 
} 


螺旋队列问题

如矩阵

1    2   3   4  5 

16 17 18 19 6

15 24 25 20 7

14 23 22 21 8

13 12 11 10 9

找出规律,并打印一个N*N的矩阵:规律就是从首坐标开始顺时针依次增大,代码如下:

#include<iostream>
using namespace std;
int a[10][10];
void fun(int n) {
	int m=1,j,i;
	for(i=0;i<n/2;i++) {
		for(j=0;j<n-i;j++) {
			if(a[i][j]==0)
				a[i][j]=m++;
		}
		
		for(j=i+1;j<n-i;j++) {
			if(a[j][n-1-i]==0)
				a[j][n-1-i]=m++;
		}
		
		for(j=n-i-1;j>i;j--) {
			if(a[n-1-i][j]==0) 
				a[n-i-1][j]=m++;
		}
		
		for(j=n-i-1;j>i;j--) {
			if(a[j][i]==0)
				a[j][i]=m++;
		}
	}
	
	if(n%2==1)
		a[n/2][n/2]=m;
}


int main() {
	int n,i,j;
	cin>>n;
	for(int i=0;i<n;i++) {
		for(int j=0;j<n;j++)
			a[i][j]=0;
	}
	
	fun(n);
	
	for(i=0;i<n;i++) {
		for(int j=0;j<n;j++) {
			cout<<a[i][j]<<" ";
		}
		cout<<endl;
	}
	return 0; 
} 


概率

输出下列程序的结果:785

#include<stdio.h>
#include<stdlib.h>
#define LOOP 1000
int main() {
	int rgnC=0;
	for(int i=0;i<LOOP;i++) {
		int x=rand();
		int y=rand();
		if(x*x+y*y < RAND_MAX * RAND_MAX)
			rgnC++;
	}
	printf("%d\n",rgnC);
	return 0;
}


分析:RAND_MAX是随机数中的最大值,相当于最大半径R。x和y是横、纵坐标上的两点。 整个题目退化成这样一个问题:随机在正方形里落1000个点,落在半径里面的点有多少个?如果落在里面一个点,则累计一次。整个问题就是求落点可能性之比,即求一个1/4圆面积和一个正方形面积之比。

1/4圆面积=(1/4)πR^2 正方形面积=R^2

两者之比=π/4;  落点数=π/4*1000=785.




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值