【C++习题笔记】谭浩强C++程序设计(第三版)第五章

1.用筛法求100之内的素数。

筛法又称为筛选法,具体做法是:先把N个自然数按次序排列起来。1不是质数,也不是合数,要划去。第二个数2是质数留下来,而把2后面所有能被2整除的数都划去。2后面第一个没划去的数是3,把3留下,再把3后面所有能被3整除的数都划去。3后面第一个没划去的数是5,把5留下,再把5后面所有能被5整除的数都划去。这样一直做下去,就会把不超过N的全部合数都筛掉,留下的就是不超过N的全部质数。因为希腊人是把数写在涂腊的板上,每要划去一个数,就在上面记以小点,寻求质数的工作完毕后,这许多小点就像一个筛子,所以就把埃拉托斯特尼的方法叫做“埃拉托斯特尼筛”,简称“筛法”。

详细解释见:https://baike.baidu.com/item/%E7%AD%9B%E9%80%89%E6%B3%95/9393288?fr=aladdin

//筛法求素数
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
	int i,j,a[100];
	for (i=0; i<100; i++)
		a[i] = i+1;
	for (i = 1; i < sqrt(100); i++)
		for (j = i+1; j < 100; j++)
		{
			if (a[i]!=1 && a[j]!=1)
				if(a[j]%a[i]==0)
					a[j]=1;
		}
	for (i = 0; i<100;i++)
	{
		if(a[i]!=1)
			cout <<a[i]<<'\t';
	}
}

这里运用了一个简便算法是,把除数a[i]限定在1到sqrt(100)的范围内,也就是后边的除数其实也是这些数的倍数,因此这样减少运算时间。

2. 用选择法对10个整数排序

简单选择排序的基本思想:第1趟,在待排序记录r[1]~r[n]中选出最小的记录,将它与r[1]交换;第2趟,在待排序记录r[2]~r[n]中选出最小的记录,将它与r[2]交换;以此类推,第i趟在待排序记录r[i]~r[n]中选出最小的记录,将它与r[i]交换,使有序序列不断增长直到全部排序完毕。

详见:https://baike.baidu.com/item/%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F%E6%B3%95/2304587?fr=aladdin

//用选择法对是个整数排序(由小到大)
#include <iostream>
using namespace std;
int main()
{
	int i,j,a[10];
	int k,temp;
	//输入
	for (i=0; i<10; i++)
		cin >> a[i];
	//排序
	for (i=0;i<9;i++)
	{
		k = i;
		for(j=i+1;j<10;j++)
			if(a[j]<a[k]) k=j;//k下标用来储存当前最小值
		temp = a[k];
		a[k] = a[i];
		a[i] = temp;
	}

	//输出
	for (i=0;i<10;i++)
		cout << a[i] <<' ';
		
}

由于要找整个数组的最小值与最前边的元素交换,因此需要随时储存并更新当前的最小值,因此需要引入一个记录当前最小值位置的索引k。

3. 求一个3 x 3整型矩阵主对角线元素之和

此处注意:不能试图通过输入大小来定义数组,数组的大小在定义时必须是确定的

即:

const int n = 5;

int a[n];

是对的,n为不可变的5,数组维度为5

而:

int n;

cin >> n;

int a[n];

是错误的

#include <iostream>
using namespace std;
int main()
{
	int i,j,a[3][3];
	for (i = 0; i < 3; i++)
		for (j = 0; j < 3; j++)
			cin >> a[i][j];
	int s = 0;
	for (i = 0; i < 3; i++)
		s = s + a[i][i];
	cout << s;
}

4. 有一个已排好序的数组,要求输入一个数后,按原来排序的规律将它插入数组中。

思路:假设原数组由小到大排列的,则当发现插入的数字大于原数组的某个元素时,将原数组从最后一个元素开始,到这个元素为止,依次向后挪一个位置,再将插入的元素放入这个元素的位置即可。

//有一个已排好序的数组,要求输入一个数后,按原来排序的规律将它插入数组中。
#include <iostream>
using namespace std;
int main()
{
	int a[11] = {1,4,5,6,9,10,22,34,67,79};
	int num,i,j;
	cin >> num;
	if (num > a[9])
     a[10]=num;
    else
    {for (i=0;i<10;i++)
     {if (a[i]>num)
       {for (j=9;j>=i;j--)
         a[j+1]=a[j];//依次往后挪一个
        a[i]=num;
		break;
       }
      }
     }
	for (i=0;i<11;i++)
		cout<<a[i]<<" ";	

}

5. 将一个数组中的值按逆序重新存放。例如,原来顺序为8,6,5,4,1。要求改为1,4,5,6,8

思路:对称位置对换即可

//将一个数组中的值按逆序重新存放。例如,原来顺序为8,6,5,4,1。要求改为1,4,5,6,8
#include <iostream>
using namespace std;
int main()
{
	const int n = 4;
	int i,t,a[n];
	for(i = 0;i<n;i++)
		cin >> a[i];
	for(i=0;i<n/2;i++)
	{
		t = a[i];
		a[i] = a[n-i-1];
		a[n-i-1] = t;
	}
	for(i=0;i<n;i++)
		cout << a[i] <<' ';
}

6. 打印杨辉三角,10行即可

思路:先把边上的1打出来,然后中间数是其上边和左上角数的加和

 //打印杨辉三角
#include <iostream>
using namespace std;
int main()
{
	const int n =10;
	int i,j,a[n][n];
	for (i=0;i<n;i++)
    {
		a[i][i]=1;
		a[i][0]=1;
    }
    for (i=2;i<n;i++)
	{
		for(j=1;j<=i-1;j++)
			a[i][j]=a[i-1][j-1]+a[i-1][j];
	}

	for (i = 0; i<10;i++)
	{
		for(j=0;j<=i;j++)
			cout << a[i][j] <<' ';
		cout << '\n';
	}
}

7.找出一个二维数组的“鞍点”,即该位置上的元素在该行上最大,在该列上最小。也可能没有鞍点。

思路:大循环找行上的最大值,然后标记该最大值及其列的位置,然后小循环判断该列有没有比最大值小的点,有则不是鞍点,继续寻找,没有则是鞍点,获得鞍点可直接跳出,则直接结束大循环。

//找出二维数组的鞍点
#include <iostream>
using namespace std;
int main()
{
	const int n=4,m=5;
	int i,j,a[n][m];
	bool flag = true;
	//输入
	for (i = 0; i < n; i++)
		for(j = 0; j <m; j++)
			cin >> a[i][j];

	//找行最大值所在的位置
	int max,maxj;
	for (i=0;i<n;i++)         
    {
		max=a[i][0]; 
		maxj=0;    
		for (j=0;j<m;j++)      //找出第i行中的最大数
		if (a[i][j]>max)
		{
			max=a[i][j];      //将本行的最大数存放在max中
			maxj=j;        //将最大数所在的列号存放在maxj中
		}

	//判断行上的最大值是不是列上的最小值
	
	int k;
	for (k = 0; k< n; k++)
	{
		if (max > a[k][maxj])
		{
			flag = false;
			continue;
		}
	}
	if(flag)             //如果flag1为真表示是鞍点
		{
			cout<<"a["<<i<<"]"<<"["<<maxj<<"]="<<max<<endl;
                      //输出鞍点的值和所在行列号
			break; //只找出一个鞍点即可
		 }
	} 
	 if(!flag)           //如果flag为假表示鞍点不存在
		cout<<"It does not exist!"<<endl;

}

8. 有15个数按由大到小顺序存放在一个数组中,输入一个数,要求用折半查找法找出该数是数组中第几个元素的值。如果该数不在数组中,则输出“无此数”。

//折半法找数
#include <iostream>
using namespace std;
int main()
{
	const int n=15;
	int i, a[n] = {1,2,4,5,6,9,10,15,18,20,21,26,30,40,60};
	int left=0,right=n-1,mid;
	int num;
	cin >> num;
	if(num>a[right] || num < a[left])
		{
			cout << "无此数";
		}
	while(left <= right)
	{
		mid = (left + right)/2;
		if (num == a[mid])
		{
			cout <<"该数所在位置为" << mid+1;
			break;
		}
		else if(num <a[mid]) //左边
		{
			right = mid - 1;
		}
		else if(num >a[mid])
		{
			left = mid + 1;
		}			
	
	}
	if(num != a[mid])
		cout << "无此数";
}

9. 给出年、月、日,计算该日在该年中是第几天。

思路:把月份的天数做成数组,按月把前边的天数相加,闰年加一天即可。

//给出年月日计算是一年的第几天
#include <iostream>
using namespace std;
int main()
{
	int year,month,day,sumday=0;
	int days_sum(int month, int day);
	int leap(int year);

	//输入
	cin >> year >> month >> day;

	//计算天数
	sumday = days_sum(month,day);

    //判断闰年
	if(leap(year) && month >= 3)
		sumday = sumday + 1;
	cout <<"该日期是一年的第:"<<sumday<<" 天";
	return 0;
}


int days_sum(int month,int day)          //计算日期 
{int i; 
   int day_tab[12]={31,28,31,30,31,30,31,31,30,31,30,31};  
   for (i=0;i<month-1;i++)
      day+=day_tab[i];
   return(day);
}    

int leap(int year)                     //判断是否为闰年 
 {int leap;
  leap=year%4==0&&year%100!=0||year%400==0;
  return(leap);
 } 

10.有一篇文章,共有3行文字,每行有个80字符.要求分别统计出其中英文大写字母、小写字母、空格以及其它字符的个数。

//统计大小写字母数
#include <iostream>
using namespace std;
int main()
{
	int i,j,upper,lower,digit,space,other;
	char text[3][80];
	upper=lower=digit=space=other=0;
	for (i=0;i<3;i++)
		{cout<<"please input line "<<i+1<<endl;
		 gets(text[i]);
		for (j=0;j<80 && text[i][j]!='\0';j++)
		{if (text[i][j]>='A'&& text[i][j]<='Z')
			upper++;
		 else if (text[i][j]>='a' && text[i][j]<='z')
			lower++;
		 else if (text[i][j]>='0' && text[i][j]<='9')
			digit++;
		 else if (text[i][j]==' ')
			space++;
		 else
			other++;
     }
   }
   cout<<"upper case:"<<upper<<endl;
   cout<<"lower case:"<<lower<<endl;
   cout<<"digit     :"<<digit<<endl;
   cout<<"space     :"<<space<<endl;
   cout<<"other     :"<<other<<endl;
   return 0;
}

11.打印以下图案

(1)用字符数组法的代码如下:

//用字符串数组打印平行四边形
#include <iostream>
using namespace std;
int main()
{
	char c[5] = {'*','*','*','*','*'};
	int i,j,k;
	for (i = 0; i < 5; i++)
	{
		for (j = 1; j<=i; j++)
			cout <<' ';
		for (k = 0; k < 5;k++)
			cout << c[k];
		cout <<'\n';
	}
}

(2)用string方法的代码如下:

要注意的是,string作为头文件要写出,否则报错。

//用string法打印平行四边形
#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str = "*****";
	int i,j;
	for (i = 0; i<5;i++)
	{
		for(j = 1; j<=i; j++)
			cout << ' ';
		cout << str << endl;   
	}
}

12. 有一行电文,已按下面规律译成密码:
    A->Z     a->z
    B->Y     b->y
    C->X     c->x
     …      …
即第一个字母变成第26个字母,第i个字母变成第(26-i+1)个字母。非字母字符不变,要求编程序将密码译回原文,并打印出密码和原文。

//电文译码
#include <iostream>
using namespace std;
int main()
{
	int j,n;
	char ch[80];
	cout<<"input cipher code:";
	gets(ch);
 
	j=0;
	while (ch[j]!='\0')
	{ 
		if ((ch[j]>='A') && (ch[j]<='Z'))
			ch[j]=155-ch[j];
		else if ((ch[j]>='a') && (ch[j]<='z'))
			ch[j]=219-ch[j];
		else
			ch[j]=ch[j];
		j++;
	 }
	n=j;
	cout<<"original text:";
	for (j=0;j<n;j++)
		putchar(ch[j]);
	cout<<endl;
	return 0;
}

注意:这里的转换相当于原文和密文字母顺序之和永远为26,也就是ACSII码和值固定,若是大写字母,则二者之和为65(A)+90(Z)=150;而小写字母为97(a)+122(z)=219,因此用和值减去密文则得到原文。

13.编写一个程序,将两个字符串连接起来,结果取代第一个字符串。
(1)  用字符数组,不用strcat函数(即自己写一个具有strcat函数功能的函数);

//字符数组连接两个字符
#include <iostream>
using namespace std;
int main()
{
	char str1[80],str2[40];
	int i=0,j=0;
	cout<<"input string1:";
	cin >> str1;
	cout<<"input string2:";
	cin >> str2;

	while(str1[i]!='\0')
		i++;
	while(str2[i]!='\0')
		str1[i++] = str2[j++];
	str1[i] = '\0';

	cout << "The new string is:"<<str1;
}


(2) 用标准库中的strcat函数;

//用strcat函数连接字符串
#include <iostream>
using namespace std;
int main()
{
	char str1[80],str2[40];
	cout<<"input string1:";
	cin >> str1;
	cout<<"input string2:";
	cin >> str2;

	cout << strcat(str1,str2);
}


(3) 用string 方法定义字符串变量。

//用sring连接字符串
#include <iostream>
#include <string>
using namespace std;
int main()
{
	string str1,str2,s;
	cout<<"input string1:";
	cin >> str1;
	cout<<"input string2:";
	cin >> str2;

	s = str1 + str2;
	cout <<s;
}

注意:用string连接两个字符串可以直接相加。

14.输出n个字符串,把它们按照字母由小到大的顺序排列并输出。

思路:冒泡法

//n个字符串排序
#include <iostream>
#include <string>
using namespace std;
int main()
{
	const int n = 5;
	int i,j;
	string str[n],temp;
	for (i = 0; i<n;i++)
		cin >> str[i];

	for (i = 0; i < n-1; i++)//冒泡
		for(j = 0; j < n-i-1;j++)
			if(str[j]>str[j+1])
			{
				temp=str[j];
				str[j]=str[j+1];
				str[j+1]=temp;
			}

	cout<<endl<<"sorted strings:"<<endl;
	for(i=0;i<n;i++)
	cout<<str[i]<<endl;
	return 0;
}

15. 输入n个字符串,把其中以字母A打头的字符串输出。 

//把字符串中A打头的字符串输出
#include <iostream>
#include <string>
using namespace std;
int main()
{
	const int n = 5;
	string str;
	int i;
	for (i = 0; i < n; i++)
	{
		cin >> str;
		if(str[0] == 'A')
			cout << str;
	}

}

16. 输入一个字符串,把其中的字符按逆序输出。如输入LIGHT,输出THGIL.
(1) 用字符数组方法;

//用字符数组逆序输出字符串
#include <iostream>
using namespace std;
int main()
{
	const int n = 5;
	char str[n],temp;
	int i;
	for (i = 0;i<n;i++)
		cin >> str[i];

	for(i = 0;i<n/2;i++)
	{
		temp = str[i];
		str[i] = str[n-i-1];
		str[n-i-1] = temp;
	}

	for(i = 0;i<n;i++)
		cout << str[i];
}


(2)用string 方法

//string方法逆转字符串
#include <iostream>
#include <string>
using namespace std;
int main()
{
	string a;
	int i,n;
	char temp;
	cout<<"please input a string:";
	cin>>a;
	n=a.size();
	for(i=0;i<n/2;i++)
	{
		temp=a[i];
		a[i]=a[n-i-1];
		a[n-i-1]=temp;

	}
	
	cout<<a<<endl;
	return 0;
}

注意:string方法有函数.size可以直接求出字符串长度

17.输入10个学生的姓名,学号和成绩,将其中不及格的姓名、学号和成绩输出。

//输出不及格学生的姓名、学号、成绩
#include <iostream>
#include <string>
using namespace std;
const int n = 10;
string name[n];
int num[n],score[n];
int main()
{
	int i;
	void input_data();
	input_data();
	cout<<endl<<"The list of failed:"<<endl;
	for(i=0;i<n;i++)
		if(score[i]<60)
			cout<<name[i]<<" "<<num[i]<<"  "<<score[i]<<endl;
	return 0;

}

void input_data()
{
	int i;
	for (i=0;i<n;i++)
    {
		cout<<"input name,number and score of student "<<i+1<<":";
		cin>>name[i]>>num[i]>>score[i];
	}
}

猜你喜欢

转载自blog.csdn.net/zl3090/article/details/85055600