1. 程式人生 > >【C++習題筆記】譚浩強C++程式設計(第三版)第四章

【C++習題筆記】譚浩強C++程式設計(第三版)第四章

1. 寫兩個函式,分別求兩個整數的最大公約數和最小公倍數,用主函式呼叫這兩個函式,並輸出結果

//兩個函式求最大公約數和最小公倍數
#include <iostream>
using namespace std;
int main()
{
	int a,b,c,d;
	int maxcm(int a, int b);
	int mincd(int a, int b);
	cin >> a >> b;	
	c = maxcm(a,b);
	cout << "最大公約數為:"<< c <<'\n';
	d = mincd(a,b);
	cout <<"最小公倍數為:"<< d <<'\n';
}

int maxcm(int a, int b)
{
	int m,n,k;
	m = a;
	n = b;
	do{
		k = m % n;
		m = n;
		n = k;
	}while(k);
	return m;
}

int mincd(int a, int b)
{
	int c,d;
	c = maxcm(a,b);
	d = a*b/c;
	return d;
}

此題注意:函式首部的形參不用在函式中再定義一次;呼叫函式時,實參前邊不用寫型別。

此題仍用的是輾轉相除法計算的最大公約數與最小公倍數,詳細解釋請見:https://blog.csdn.net/zl3090/article/details/84614046

2.  求方程ax2+bx+c=0的根.用三個函式分別求當:b2-4ac大於0、等於0和小於0時的根並輸出結果。在主程式中輸入a,b,c的值。

//三個函式求二次方程的根
#include <iostream>
#include <cmath>
using namespace std;	
float r1,r2;//全域性變數,實根
float p, q;//虛根
int main()
{
	float a,b,c;
	float t;
	void root1(float a, float b, float c);//大於0
	void root2(float a, float b, float c);//等於0
	void root3(float a, float b, float c);//小於0
	cin >> a >> b >> c;
	
	//判別式計算
	t = b*b - 4*a*c;

	//分情況
	if (t>0)
	{
		root1(a,b,c);
		cout << "r1 = " << r1 << '\t'<< "r2 = " << r2 <<'\n';
	}
	else if (t == 0)
	{
		root2(a,b,c);
		cout << "r1 = " << r1 << '\t'<< "r2 = " << r2 <<'\n';
	}
	else
	{
		root3(a,b,c);
		cout<<"r1="<< p <<'+'<< q <<'i'<<'\n';
		cout<<"r2="<< p <<'-'<< q <<'i'<<'\n';
	}

}

void root1(float a, float b, float c)
{
	r1 = (-b+sqrt( b*b - 4*a*c))/(2*a);
	r2 = (-b-sqrt( b*b - 4*a*c))/(2*a);
}

void root2(float a, float b, float c)
{
	r1 = r2 = (-b)/(2*a);
}
void root3(float a, float b, float c)
{
	p = -b/(2*a);;
	q = sqrt(-(b*b - 4*a*c))/(2*a);
}

此題注意的是,在一個函式中如果想實現多個輸出,最簡單的方法就是全域性變數和void函式的結合

還有其他方法可見:https://blog.csdn.net/qq_34489443/article/details/81274951

3. C++程式 寫一個判斷素數的函式,在主函式輸入一個整數,輸出是否為素數的資訊。

//素數的判別函式
#include <iostream>
using namespace std;
int main()
{
	int a,r;
	r = 0;
	int prime(int a);
	cin >> a;
	r = prime(a);
	if (r == 1)
		cout << a <<"是素數";
	else
		cout << a <<"不是素數";
}

int prime(int a)
{
	int i,r;
	r = 1;
	for (i=2;i<a/2;i++)
	{
		if (a % i == 0)
		{
			r = 0; break;
		}
	}
	return r;
}

此題注意:素數即質數,優化在於for迴圈中放的是2到a/2之間的數字,只考慮一半即可,因為另一半是和前一半配對的。

4.  求a!+b!+c!的值,用一個函式fac(n)求n!。a,b,c的值由主函式鍵入,最終的值在主函式中輸出。

//遞迴求階乘
#include <iostream>
using namespace std;
int main()
{
	int a,b,c,s;
	int fac(int a);
	cin >> a >> b >> c;
	s = fac(a) + fac(b) +fac(c);
	cout << a << ','<< b << ','<< c<<"的階乘之和為"<< s <<'\n';
}
int fac(int a)
{
	long r;
	r = 0;
	if (a <0)
		cout <<"error";
	else if (a == 1 || a == 0)
		r = 1;
	else
	{
		r = a * fac(a-1);
	}
	return r;
}

此題注意,輸出的階乘為long型,不然太容易溢位。

5.  寫一函式求sinh(x)的值,求sinh(x)的近似公式為 sinh(x)=(ex-e(-x))/2其中用一個函式求ex  (x在指數位置)

//ex函式的複合函式
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
	double x,sh;
	double ex(double x);
	cin >> x;
	sh = (ex(x) - ex(-x))/2;
	cout << "sinh(x)的值為:"<< sh <<'\n';
}

double ex(double x)
{
	double e;
	e = exp(x);
	return e;
}

6. 用牛頓迭代法求根。方程為ax3+bx2+cx+d=0  係數a,b,c,d的值依次為1,2,3,4,  由主函式輸入。求x在1附近的一個實根。求出根後由主函式輸出。

牛頓迭代法公式詳見:https://baike.baidu.com/item/%E7%89%9B%E9%A1%BF%E8%BF%AD%E4%BB%A3%E6%B3%95/10887580?fr=aladdin

//牛頓迭代法求根
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
	double a,b,c,d,r;
	double newton(double a, double b, double c, double d);
	cin >> a >> b >> c >>d;
	r = newton(a,b,c,d);
	cout << "牛頓迭代法所得的根為:"<< r;

}

double newton(double a, double b, double c,double d)
{
	double x= 1,x0,f,f1;
	do {
		x0 = x;
		f=((a*x0+b)*x0+c)*x0+d;
		f1=(3*a*x0+2*b)*x0+c;//一階導
		x=x0-f/f1;
	}while(fabs(x-x0)>=1e-5);
	return x;
}

do-while的用法還要加強

7.  寫一個函式驗證哥德巴赫猜想:一個不小於6的偶數可以表示為兩個素數之和,如6=3+3,8=3+5,10=3+7……在主函式輸入一個不小於6的偶數N。然後呼叫函式gotbaha,在gotbaha函式中再呼叫prime函式,prime函式的作用是判別一個數是否為素數。在godbah函式中輸出以下形式的結果:34=3+31

//哥德巴赫猜想
#include <iostream>
using namespace std;
int main()
{
	int e,flag = 0;
	int gotbaha(int e);
	cin >> e;
	flag = gotbaha(e);
	if (flag == 1)
		cout << "gotbaha is true.";
}
int gotbaha(int e)
{
	int a,b,flag = 0;
	int prime(int a);
	if (e <=5 || e % 2 !=0 )
		cout << "Please enter odd number";
	else
	{
		for(a=3;a<=e/2;a=a+2)
		{
			if(prime(a)) 
			{
				b=e-a;
				if (prime(b))
					flag = 1;
	        }
		}
	}
	return flag;
}

int prime(int a)
{
	int i,r;
	r = 1;
	for (i=2;i<a/2;i++)
	{
		if (a % i == 0)
		{
			r = 0; break;
		}
	}
	return r;
}

此題的關鍵在於如何把一個偶數拆成兩個奇數的和,然後分別驗證這兩個奇數是不是素數。

8. 用遞迴方法求n階勒讓德多項式的值,遞迴公式為:

//遞迴求值
#include <iostream>
using namespace std;
int main()
{
	float n,x,r;
	float p(float n,float x);
	cin >> n >> x;
	r = p(n,x);
	cout << "公式的值為"<< r ;

}

float p(float n, float x)
{
	if (n==0)
		return(1);
	else if (n==1)
		return(x);
	else
		return(((2*n-1)*x*p((n-1),x)-(n-1)*p((n-2),x))/n);
}

9. Hanoi(漢諾)塔問題。這是一個經典的數學問題:古代有一個梵塔,塔內有3個座A,B,C,開始時A座上有64個盤子,盤子大小不等,在的在下,小的在上(見下圖)。
有一個老和尚想把這64個盤子從A盤移到C座,但每次只允許移動一個盤,且在移動過程中有3個座上都始終保持在大盤在下,小盤在上。在移動過程中可以利用B座,要求編寫程式打印出移動的步驟。

解題思路:採用遞迴方法,關鍵在於可以逆向思考,即不考慮前邊n-1個盤子是怎麼移動的,直接考慮最後一次移動的情況,由題意知,A為原始塔,B為輔助塔,C為目標塔,分為以下三步:

(1)先把A上的n-1個盤子移動到B上(不考慮具體過程,交給遞迴);

(2)然後把A中最後一個盤子移動到C上;

(3)此時B成為原塔,A為輔助塔,將B中n-2個盤子放到A上(仍不考慮具體過程,交給遞迴);

此時,一輪移動已結束,下一次的開始,將B中的一個剩下的一個放在C上

理解過程如下動畫所示:(參考自:https://www.cnblogs.com/wuzhenbo/p/3496054.html

三個圓盤的漢諾塔

 

四個圓盤的漢塔:

程式碼如下:

//漢諾塔
#include <iostream>
using namespace std;
int main()
{
	int n;
	char x, y ,z;
	void Hanoi(int n, char x, char y, char z);//原塔,輔助塔,目標塔
	cin >> n;
	Hanoi(n,'A','B','C');
}

void Hanoi(int n, char x, char y, char z)
{
	if (n == 1) cout<<"From "<< x <<" To "<<z <<'\t';
	else
	{
		Hanoi(n-1,x,z,y); //將n-1個盤子從x移動到y
		cout <<"From "<< x <<" To "<<z <<'\t';//將第n個盤子移動到z
		Hanoi(n-1,y,x,z);//將y上的盤子移動到z
	}
}

10. 用遞迴法將一個整數n轉換成字串。例如 輸入483,應輸出字串“483”。n的倍數不確定,可以是任意倍數的整數。 

//遞迴將數字轉為字串
#include <iostream>
using namespace std;
int main()
{
	int n;
	void convert(int n);
	cin >> n;
	if (n<0)
	{
		cout << "-";
		n = -n;
	}
	convert(n);
}

void convert(int n)
{
	int i;
	char c;
	if ((i =n/10) != 0)
		convert(i);
	c = n % 10 + '0';
	cout<<" "<<c;
}

單個數字變字串,給它+‘0’即可

11. 用遞迴方法求

n的值由主函式輸入。

//遞迴求函式值
#include <iostream>
using namespace std;
int main()
{
	int n,s;
	int fac (int n);
	cin >> n;
	s = fac(n);
	cout <<"函式的值為:"<< s;
}

int fac(int n)
{
	int s;
	if (n==1)
		s = n*n;
	else
		s = n*n + fac(n-1);
	return s;
}

12. 三角形的面積為 area=s*(s-a)*(s-b)*(s-c)  其中,s=1/2*(a+b+c),  a , b, c 為三角形的三邊。定義兩個帶引數的巨集,一個用來求S,另一個用來求 area 。 編寫程式,在程式中用帶實參的巨集名來求面積。 

//帶實參的巨集求三角形面積
#include <iostream>
#include <cmath>
using namespace std;
#define S(a,b,c)  (a+b+c)/2
#define AREA(a,b,c) sqrt(S(a,b,c)*(S(a,b,c)-a)*(S(a,b,c)-b)*(S(a,b,c)-c))
int main()
 {float a,b,c;
  cout<<"input a,b,c:";
  cin>>a>>b>>c;
  if (a+b>c && a+c>b && b+c>a)
    cout<<"area="<<AREA(a,b,c)<<endl;
  else
    cout<<"It is not a triangle!"<<endl;
  return 0;
 } 

這裡使用了巨集作為簡易函式的用法,關於巨集用法的總結請見:

https://blog.csdn.net/zl3090/article/details/84750896