《面向对象程序设计》OJC++类的构造、析构、拷贝构造、静态成员综合题

1.彩票复制(拷贝构造)

题目描述

假设每组彩票包含6个号码,设计一个彩票类lottery,数据成员包括第一组号码、其他组数、其他组号码,描述如下

1、第一组号码group1,整数数组,长度为6

2、其他组数num,表示以第一组号码为样本,创建num组其他号码

3、其他组号码groupn,整数指针(int **),,该数据将动态创建二维整数数组,共9行,每行包含6个号码。

彩票类的成员函数包括:构造函数、拷贝构造函数、打印,描述如下:

1、打印函数,输出彩票的所有组的号码

2、构造函数,两个参数,第一个参数为整数数组,对应第一组号码,第二个参数为整数,表示其他组数(不超过9)。注意在构造函数中,其他组号码groupn不动态分配空间,仍然为指针

3、拷贝构造函数,其他组号码groupn动态创建二维数组,根据其他组数创建其他组的号码,创建规则为:

a)第i组的第j个号码等于上一组第j-1个号码加1,首个号码等于上一组最后一个号码加1

例如第一组号码group1的号码是1、3、5、7、9、11,且其他组数为2

则groupn的第0组号码是12、2、4、6、8、10,第1组号码是11、13、3、5、7、9,以此类推

输入

第一行输入t表示有t个样例,每个样例对应一行数据

接着一行输入7个参数,前6个参数表示首张彩票的第一组6个号码,第7个参数表示其他组数,这时使用使用构造函数

然后采用拷贝构造方法生成第二张彩票,其中复制了首张彩票的第一组号码和其他组数,并且生成其他组号码

依此类推

输出

调用Print方法,输出每个样例中第二张彩票的所有组的号码

输入样例

2
1 3 5 7 9 11 2
22 44 66 88 100 122 3

输出样例

1 3 5 7 9 11
12 2 4 6 8 10
11 13 3 5 7 9
22 44 66 88 100 122
123 23 45 67 89 101
102 124 24 46 68 90
91 103 125 25 47 69

#include<iostream>
#include<cstring>
using namespace std;
class lottery
{
private:
	int group1[6];
	int num;
	int** groupn;
public:
	lottery() {};
	lottery(int a[6], int n)
	{
		for (int i = 0; i < 6; i++)
		{
			group1[i] = a[i];
		}
		num = n;
		groupn = nullptr;//初始指向空
	}
	lottery(lottery& l)//拷贝构造
	{
		num = l.num;
		for (int i = 0; i < 6; i++)
		{
			group1[i] = l.group1[i];
		}
		groupn = new int* [num];
		for (int i = 0; i < num; i++)
		{
			groupn[i] = new int[6];
		}
		for (int i = 0; i < 6; i++)
		{
			if (i == 0)
				groupn[0][i] = group1[5] + 1;
			else
				groupn[0][i] = group1[i-1] + 1;
		}
		for (int i = 1; i < num; i++)
		{
			groupn[i][0] = groupn[i - 1][5] + 1;
			for (int j = 1; j < 6; j++)
			{
				groupn[i][j] = groupn[i - 1][j - 1] + 1;
			}
		}
	}
	void print()
	{
		for (int i = 0; i < 6; i++)
		{
			if (i < 5)cout << group1[i] << " ";
			else cout << group1[i] << endl;
		}
		for (int i = 0; i < num; i++)
		{
			for (int j = 0; j < 6; j++)
			{
				if (j < 5)
					cout << groupn[i][j] << " ";
				else
					cout << groupn[i][j] << endl;
			}
		}
	}
	~lottery()
	{
		if (groupn != nullptr)
		{
			for (int i = 0; i < num; i++)
			{
				delete[]groupn[i];
			}
			delete[]groupn;
		}
	}
};
int main()
{
	int n;
	cin >> n;
	while (n--)
	{
		int a[6] = { 0 };
		for (int i = 0; i < 6; i++)
		{
			cin >> a[i];
		}
		int zu;
		cin >> zu;
		lottery ll(a, zu);
		lottery l2(ll);
		l2.print();
	}
	return 0;
}

2.电话号码升位(拷贝构造函数)

题目描述

定义一个电话号码类CTelNumber,包含1个字符指针数据成员,以及构造、析构、打印及拷贝构造函数。

字符指针是用于动态创建一个字符数组,然后保存外来输入的电话号码

构造函数的功能是为对象设置键盘输入的7位电话号码,

拷贝构造函数的功能是用原来7位号码的对象升位为8位号码对象,也就是说拷贝构造的对象是源对象的升级.电话升位的规则是原2、3、4开头的电话号码前面加8,原5、6、7、8开头的前面加2。

注意:合法的电话号码:1、长度为7位;2、电话号码的字符全部是数字字符;3、第一个字符只能是以下字符:2、3、4、5、6、7、8。与上述情况不符的输入均为非法

输入

测试数据的组数 t

第一个7位号码

第二个7位号码

......

输出

第一个号码升位后的号码

第二个号码升位后的号码

......

如果号码升级不成功,则输出报错信息,具体看示例

输入样例

3
6545889
3335656
565655

输出样例

26545889
83335656
Illegal phone number

AC代码

#include<iostream>
#include<cstring>
#include<ctype.h>
using namespace std;
class CTelNumber
{
	char* number;
public:
	CTelNumber();
	CTelNumber(char* n)
	{
		number = new char[8];
		for (int i = 0; i <=7; i++)//包括结尾符号
		{
			number[i] = n[i];
		}	
	}
	CTelNumber(CTelNumber& c)
	{
		number= new char[9];
		if (c.number[0] == '2' || c.number[0] == '3' || c.number[0] == '4')
		{
			*number = '8';
			for (int i = 0; i < 9; i++)
			{
				*(number + i + 1) = *(c.number + i);
			}
		}
		else
		{
			*number = '2';
			for (int i = 0; i < 9; i++)
			{
				*(number + i + 1) = *(c.number + i);
			}
		}

	}
	void print()
	{
		cout << number << endl;
	}
	~CTelNumber()
	{
		delete[]number;
	}
};
int main()
{
	int n;
	cin >> n;
	while (n--)
	{
		char s[8];
		cin >> s;
		bool flag = true;
		if (strlen(s) == 7)
		{
			for (int i = 0; i < 7; i++)
			{
				if (s[0] >= '2' && s[0] <= '8')
					flag = true;
				else
				{
					flag = false;
					break;
				}
				if (s[i] >= '0' && s[i] <= '9')
				{
					flag = true;
				}
				else
				{
					flag = false;
					break;
				}
			}
			if (flag)
			{
				CTelNumber c1(s);
				CTelNumber c2(c1);
				c2.print();
			}
			else
			{
				cout << "Illegal phone number" << endl;
			}
		}
		else
		{
			cout << "Illegal phone number" << endl;
		}
	}
	return 0;
}

3.【程序填空】Tutor类(拷贝构造)

题目

已知主函数和Tutor类,请根据输入输出完成STU类定义

输入

输入一个参数,作为全局变量IDs的初始值,用于输出结果提示,看样例

输出

具体看样例

输入样例

100

输出样例

Construct student Tom
Construct student Tom_copy
Construct tutor 100
Calling fuc()
Construct student Tom_copy_copy
In function fuc()
Destruct tutor 101
Destruct student Tom_copy_copy
Destruct tutor 101
Destruct student Tom_copy
Destruct student Tom
AC代码:

#include <iostream>
#include <string>
#include <cstring>
using namespace std;
//填空实现类STU的定义
/********** Write your code here! **********/
class STU
{
private:
	string name;
public:
	STU(string s1)
	{
		name = s1;
		cout << "Construct student " << name << endl;
	}
	STU(STU& s)
	{
		name = s.name + "_copy";
		cout << "Construct student " << name << endl;
	}
	~STU()
	{
		cout << "Destruct student " << name << endl;
	}

};
/*******************************************/
//其他代码如下
int IDs; //全局变量,用于输出结果提示
class Tutor {
private:
	STU stu;
public:
	Tutor(STU& s) : stu(s)
	{
		cout << "Construct tutor " << IDs << endl;
	}
	~Tutor()
	{
		cout << "Destruct tutor " << IDs << endl;
	}

};
void fuc(Tutor x)
{
	cout << "In function fuc()" << endl;
}

int main()
{
	cin >> IDs;
	STU s1("Tom"); //输入学生姓名Tom
	Tutor t1(s1);
	IDs++;
	cout << "Calling fuc()" << endl;
	fuc(t1);

	return 0;
}

4.手机服务(构造+拷贝构造+堆)

题目描述

设计一个类来实现手机的功能。它包含私有属性:号码类型、号码、号码状态、停机日期;包含方法:构造、拷贝构造、打印、停机。

1、号码类型表示用户类别,只用单个字母,A表示机构,B表示企业、C表示个人

2、号码是11位整数,用一个字符串表示

3、号码状态用一个数字表示,1、2、3分别表示在用、未用、停用

4、停机日期是一个日期对象指针,在初始化时该成员指向空,该日期类包含私有属性年月日,以及构造函数和打印函数等

----------------------------------------

5、构造函数的作用就是接受外来参数,并设置各个属性值,并输出提示信息,看示例输出

6、拷贝构造的作用是复制已有对象的信息,并输出提示信息,看示例输出。

想一下停机日期该如何复制,没有停机如何复制??已经停机又如何复制??

7、打印功能是把对象的所有属性都输出,输出格式看示例

8、停机功能是停用当前号码,参数是停机日期,无返回值,操作是把状态改成停用,并停机日期指针创建为动态对象,并根据参数来设置停机日期,最后输出提示信息,看示例输出

-------------------------------------------

要求:在主函数中实现号码备份的功能,对已有的虚拟手机号的所有信息进行复制,并将号码类型改成D表示备份;将手机号码末尾加字母X

输入

第一行输入t表示有t个号码

第二行输入6个参数,包括号码类型、号码、状态、停机的年、月、日,用空格隔开

依次输入t行

输出

每个示例输出三行,依次输出原号码信息、备份号码信息和原号码停机后的信息

每个示例之间用短划线(四个)分割开,看示例输出

输入样例

2
A 15712345678 1 2015 1 1
B 13287654321 2 2012 12 12

输出样例

Construct a new phone 15712345678
类型=机构||号码=15712345678||State=在用
Construct a copy of phone 15712345678
类型=备份||号码=15712345678X||State=在用
Stop the phone 15712345678
类型=机构||号码=15712345678||State=停用 ||停机日期=2015.1.1
----
Construct a new phone 13287654321
类型=企业||号码=13287654321||State=未用
Construct a copy of phone 13287654321
类型=备份||号码=13287654321X||State=未用
Stop the phone 13287654321
类型=企业||号码=13287654321||State=停用 ||停机日期=2012.12.12
----
AC代码:

#include<iostream>
#include<cstring>
#include<ctype.h>
using namespace std;
class Date
{
private:
	int year;
	int month;
	int day;
public:
	Date() {};
	Date(int y, int m, int d)
	{
		year = y;
		month = m;
		day = d;
	}
	int getyear()
	{
		return year;
	}
	int getmonth()
	{
		return month;
	}
	int getday()
	{
		return day;
	}
	void print()//特殊打印停机日期
	{
		cout << "停机日期="<<year << '.' << month << '.' << day << endl;
	}
};
class phone
{
private:
	char type;
	string number;
	int condition;
	Date* time;
public:
	phone(char ch, string n, int c)
	{
		type = ch;
		number = n;
		condition = c;
		time = NULL;
		cout << "Construct a new phone " << number << endl;
	}
	phone(phone& p)
	{
        //进行初始
		type = 'D';//D表示备份
		condition = p.condition;
		time = NULL;
		if (p.time != NULL)
		{
			time = new Date(*p.time);//time为对象指针类型
		}
		number = p.number;
		cout << "Construct a copy of phone " << number << endl;
		number += 'X';
	}
	void stop(Date& d)//
	{
		condition = 3;
		time = new Date(d.getyear(), d.getmonth(), d.getday());//time本来指空,后赋值
		cout << "Stop the phone " << number << endl;
	}
	string gettype()
	{
		switch (type)//用switch
		{
		case'A':return"机构";
		case'B':return"企业";
		case'C':return"个人";
		case'D':return"备份";
		}
	}
	string getcondition()
	{
		switch (condition)
		{
		case 1:return"在用";
		case 2:return"未用";
		case 3:return"停用";
		}
	}
	void print()
	{
		cout << "类型=" << gettype() << "||号码=" << number << "||State=" << getcondition();
		if (condition == 3)//若停用特殊处理
		{
			cout << " ||";
			time->print();
		}
		else cout << endl;
	}
	~phone()
	{
		if (time != NULL)
			delete time;
	}
};
int main()
{
	int t, y, m, d, s;
	char ty;
	string nn;
	cin >> t;
	while (t--)
	{
		cin >> ty >> nn >> s >> y >> m >> d;
		Date dd(y, m, d);
		phone p1(ty, nn, s);
		p1.print();
		phone p2(p1);
		p2.print();
		p1.stop(dd);
		p1.print();
		cout << "----" << endl;
	}
	return 0;
}

5.生日打折(复合类构造)

题目描述

定义一个日期类Date,包含数据成员year\month\day,还包含构造函数及其他函数(根据需要自己添加)

定义一个会员类VIP,包含数据成员id和birth,其中id是整数表示会员编号;birth是Date类型表示生日。

类VIP包含构造函数和其他函数(根据需要自己添加),还包含一个折扣函数Discount。函数Discount返回结果为浮点数表示折扣,函数包含1个参数为日期类型,函数功能是判断参数日期是否会员生日,是则折扣为0.5,不是则折扣为0.95

编写程序实现上述类功能并实现输入输出的要求

输入

第一行输入年、月、日,表示今天日期

第二行输入t表示有t个会员

第三行输入第1个会员的ID、生日的年、月、日

第四行输入第1个会员的消费金额

依次类推输入下一个会员的两行数据.....

输出

根据会员的消费金额,调用Discount函数判断今天是否会员生日并得到折扣,然后计算会员打完折的消费金额

每一行先输出会员编号,再输出会员打完折的消费金额,消费金额只需要输出整数部分

提示把浮点数转整数

double x = 123.456

cout<<int(x)<<endl;

输入样例

2017 4 20
2
1111 2000 4 20
136
2222 2000 3 30
125

输出样例

1111's consumption is 68
2222's consumption is 118

AC代码:

#include<iostream>
#include<cstring>
#include<ctype.h>
using namespace std;
class Date
{
private:
	int year;
	int month;
	int day;
public:
	Date();
	Date(int yy,int mm,int dd)
	{
		year = yy;
		month = mm;
		day = dd;
	}
	int gety()
	{
		return year;
	}
	int getm()
	{
		return month;
	}
	int getd()
	{
		return day;
	}
};
class VIP
{
private:
	int id;
	Date birth;
public:
	VIP(int t, int yy, int mm, int dd) :id(t), birth(yy, mm, dd) {};//类嵌套初始化
	double Discount(Date d)
	{
		if (birth.getm() == d.getm() && birth.getd() == d.getd())
		{
			return 0.5;
		}
		else return 0.95;
	}
};
int main()
{
	int y, m, d;
	cin >> y >> m >> d;
	Date today(y,m,d);
	int t;
	cin >> t;
	for (int i = 1; i <= t; i++)
	{
		int idd, yy, mm, dd;
		cin >> idd >> yy >> mm >> dd;
		VIP pp(idd, yy, mm, dd);
		double money;
		cin >> money;
		money = money * pp.Discount(today);
		cout << idd << "'s consumption is " << int(money) << endl;
	}
	return 0;
}

6.最高成绩(静态成员)

题目描述

学生类定义如下:

class Student {

private:

int id;//学号

int score; //成绩

static int  maxscore;//最高分数

static int maxid;//最高分数学生学号

public:

Student(int ti=0,int ts=0)

:id(ti), score(ts)

{}

static void findMax(Student & st); //寻找最高成绩和学号

static int getMaxScore(); //返回最高成绩

static int getMaxID();//返回最高成绩的学号

};

输入一组学生学号和成绩,用上述静态成员求最高成绩和对应学号

输入

第一行输入n表示有n个学生

接着输入n行,每行包括两个数据,表示学号和成绩

输出

调用静态成员函数输出学号和最高成绩,格式看样例

输入样例

3
1002 68
1023 54
1045 32

输出样例

1002--68

AC代码:

#include<iostream>
#include<cstring>
#include<ctype.h>
#include<vector>
using namespace std;
class Student {
private:
	int id;//学号
	int score; //成绩
	static int  maxscore;//最高分数
	static int maxid;//最高分数学生学号
public:
	Student(int ti = 0, int ts = 0):id(ti), score(ts){}
	static void findMax(Student& st); //寻找最高成绩和学号
	static int getMaxScore()//返回最高成绩(且为静态类型)
	{
		return maxscore;
	}
	static int getMaxID()//返回最高成绩的学号(且为静态类型)
	{
		return maxid;
	}
};
void Student::findMax(Student& st)
{
	if (st.score > Student::maxscore)//访问私有静态成员
	{
		Student::maxscore = st.score;
		Student::maxid = st.id;
	}
}
//初始类里的静态成员
int Student::maxid = 0;
int Student::maxscore = 0;
int main()
{
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		int idd, ss;
		cin >> idd >> ss;
		Student s(idd, ss);
		Student::findMax(s);//使用静态成员函数
		
	}
    //输出静态成员函数
	cout << Student::getMaxID() << "--" << Student::getMaxScore()<< endl;
	return 0;
}

7.NBA选秀(静态成员)

题目描述

 定义一个Player类,要求输入球员的姓名,比赛位置以及球探评分,创建一个Player对象。

记录静态成员变量,记录本届选秀大会中各个位置的球员数量。

注:比赛位置一共有5种,分别位PG,SG,SF,PF,C

输入

 输入多位球员信息。包括名字,比赛位置,球探评分

输入0结束

输出

 输出每一位球员的信息

输出本届选秀大会的球员位置统计结果

输入样例

James SF 98
Curry PG 97
Davis PF 95
Durant SF 97
Oneal C 99
Kuzma SF 82
0

输出样例

Name:James Position:SF Rate:98
Name:Curry Position:PG Rate:97
Name:Davis Position:PF Rate:95
Name:Durant Position:SF Rate:97
Name:Oneal Position:C Rate:99
Name:Kuzma Position:SF Rate:82

Total PG Player:1
Total SG Player:0
Total SF Player:3
Total PF Player:1
Total C Player:1

AC代码:

#include<iostream>
#include<cstring>
#include<ctype.h>
#include<vector>
using namespace std;
class Player
{
private:
	string name;
	string position;
	int score;
	static int pg;
	static int sg;
	static int sf;
	static int pf;
	static int c;
public:
	Player(string s1, string s2, int n) :name(s1), position(s2), score(n){}
    void add(string s)
	{
		if (s == "SG")sg++;
		if (s == "PG")pg++;
		if (s == "PF")pf++;
		if (s == "SF")sf++;
		if (s == "C")c++;
	}
	static int getsg()//由于sg为静态类型,返回时也是static int类型
	{
		return sg;
	}
	static int getpg()
	{
		return pg;
	}
	static int getpf()
	{
		return pf;
	}
	static int getsf()
	{
		return sf;
	}
	static int getc()
	{
		return c;
	}
	void print()
	{
		cout << "Name:" << name << " Position:" << position << " Rate:" << score << endl;
	}
};
//初始静态成员
int Player::pg = 0;
int Player::sg = 0;
int Player::sf = 0;
int Player::pf = 0;
int Player::c = 0;
int main()
{
	string n,n1, p,p1;
	int f,f1;
	cin >> n >> p >> f;
	n1 = n;
	p1 = p;
	f1 = f;
	while (n != "0")
	{
		Player pp(n1, p1, f1);
		pp.add(p1);
		pp.print();
		cin >> n;
		if (n == "0")break;
		else
		{
			cin >> p >> f;
			n1 = n;
			p1 = p;
			f1 = f;
		}
	}
	cout << endl;
	cout << "Total PG Player:" << Player::getpg() << endl;
	cout << "Total SG Player:" << Player::getsg() << endl;
	cout << "Total SF Player:" << Player::getsf() << endl;
	cout << "Total PF Player:" << Player::getpf() << endl;
	cout << "Total C Player:" << Player::getc() << endl;
	return 0;
}

8.对象的构造与析构(构造与析构)

题目描述

如下所示为类对象构造和析构过程中产生的输出,试完成类的定义和主函数的编写.

输入

测试数据的组数t

第一组对象个数n1

第二组对象个数n2

.......

输出

Constructing object 1
Constructing object 2

......
Constructing object n1
Destructing object n1

......
Destructing object 2
Destructing object 1

Constructing object 1
Constructing object 2

......
Constructing object n2
Destructing object n2

......
Destructing object 2
Destructing object 1

......

样例查看模式 

输入样例

2
3
4

输出样例

Constructing object 1
Constructing object 2
Constructing object 3
Destructing object 3
Destructing object 2
Destructing object 1
Constructing object 1
Constructing object 2
Constructing object 3
Constructing object 4
Destructing object 4
Destructing object 3
Destructing object 2
Destructing object 1

AC代码

#include<iostream>
#include<cstring>
#include<ctype.h>
#include<vector>
using namespace std;
class X
{
	int num;
public:
	X(int n)
	{
		num = n;
		for(int i=1;i<=num;i++)//先从小到大
		cout << "Constructing object " << i << endl;
	}
	~X()
	{
		for (int i = num; i >0; i--)//后从大到小
			cout << "Destructing object " << i << endl;
	}
};
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int x;
		cin >> x;
		X xx(x);
        //实际构造和析构都是一次
	}
	return 0;
}

9.三角形类(构造与析构)

题目描述

定义一个三角形类CTriangle,属性包含三条边和三角形类型,其中用字符串保存三角形类型。三角形类型如下:

等腰三角形:isosceles triangle
直角三角形:right triangle
等腰直角三角形:isosceles right triangle
等边三角型:equilateral triangle
一般三角形:general triangle
不能构成三角形:no triangle

其中判断直角三角形条件:三角形三边中的一边长度平方等于另两边长度平方之和

类行为包括构造、析构、计算面积等等。其中构造函数将设置三条边长度,并且判断三条边能否构成三角形、并设置三角形类型。析构函数将三条边长度清0,并将三角形类型设置为none

三角形面积计算如下

输入

测试数据的组数

第一组边1 第一组边2  第一组边3

第二组边1 第二组边2 第二组边3

......

输出

第一个三角形类型,面积

第二个三角形类型,面积

......

如果不形成三角形,就无需输出面积

面积精度到小数点后1位

输入样例

3
3.0 2.0 6.0
3.0 4.0 5.0
1.0 1.0 1.414

输出样例

 no triangle
right triangle, 6.0
isosceles right triangle, 0.5

AC代码

#include<iostream>
#include<cstring>
#include<ctype.h>
#include<vector>
#include<cmath>
#include<iomanip>
using namespace std;
#define l 0.001//当比较两个浮点数是否相等时要用到
class CTriangle
{
private:
	double x, y, z;
	double S;
	string type;
public:
	CTriangle(double xx, double yy, double zz)
	{
		x = xx;
		y = yy;
		z = zz;
		if (x + y < z || y + z < x || z + x < y)
		{
			type = "no triangle";
		}
		else
		{
			if (fabs(x-y)<l && fabs(y-z)<l)
			{
				type = "equilateral triangle";
			}
			else if (fabs(x-y)<l || fabs(y-z)<l || fabs(x-z)<l)
			{
				if (fabs(x * x + y * y - z * z)<l || fabs(y * y + z * z - x * x)<l ||fabs( x * x + z * z - y * y)<l)
				{
					type = "isosceles right triangle";
				}
				else
					type = "isosceles triangle";
			}
			else
			{
				if (fabs(x * x + y * y - z * z) < l || fabs(y * y + z * z - x * x) < l || fabs(x * x + z * z - y * y) < l)
				{
					type = "right triangle";
				}
				else
					type = "general triangle";
			}
		}
	}
	double Sget()
	{
		double L = (x + y + z) / 2;
		return sqrt(L * (L - x) * (L - y) * (L - z));
	}
	string tget()
	{
		return type;
	}
	~CTriangle()
	{
		x = 0;
		y = 0;
		z = 0;
		type = "none";
	}
};
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		double x1, x2, x3;
		cin >> x1 >> x2 >> x3;
		CTriangle c(x1,x2,x3);
		if (c.tget() == "no triangle")
		{
			cout << "no triangle" << endl;
		}
		else
		{
			cout << c.tget() << ", " << fixed << setprecision(1) << c.Sget() << endl;
		}

	}
	return 0;
}

 10.找出某个范围内的所有素数(构造与析构)

题目描述

埃拉托斯特尼筛法简称埃氏筛或爱氏筛,是一种由希腊数学家埃拉托斯特尼所提出的一种简单检定素数的算法。要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数剔除,剩下的就是素数。

给出要筛数值的范围n,找出以内的素数。先用2去筛,即把2留下,把2的倍数剔除掉;再用下一个质数,也就是3筛,把3留下,把3的倍数剔除掉;接下去用下一个质数5筛,把5留下,把5的倍数剔除掉;不断重复下去......。

采用埃拉托斯特尼筛法求素数的算法可用以下CSieve类来实现:
class CSieve
{
private:
char *p_sieve;
unsigned long num;                //num是最大范围
public:
CSieve(unsigned long n);
void printPrime();
~CSieve();
};

其中p_sieve为数组指针, p_sieve[i]=1表示i是素数, p_sieve[i]=0表示i不是素数。编写程序采用上述类来打印某个范围内的所有素数。

输入

测试数据的组数

n1

n2

......

输出

2到n1的所有素数

2到n2的所有素数

......

输入样例

2
10
20

输出样例

2 3 5 7
2 3 5 7 11 13 17 19

AC代码

#include<iostream>
#include<cstring>
#include<ctype.h>
#include<vector>
#include<cmath>
#include<iomanip>
using namespace std;
class CSieve
{
private:
	char* p_sieve;
	unsigned long num;                //num是最大范围
public:
	CSieve(unsigned long n)
	{
		num = n;
		p_sieve= new char[n];
		fill(p_sieve, p_sieve + n, '1');//让p_sieve数组全为1
	}
	void printPrime()
	{
        //注意for里i的定义
        //素数为1,合数为0
		for (unsigned long i = 2; i <= num ; i++)
		{
			if (p_sieve[i] == '0')continue;
				for (int j = 2*i; j<= num; j+=i)
				{
					p_sieve[j] = '0';
				}
		}
		for (unsigned long i = 2; i <= num; i++)
		{
			if (p_sieve[i] == '0')continue;
			if (i != 2)cout << " ";
			cout << i;
		}
		cout << endl;
	}
	~CSieve()
	{
		delete[]p_sieve;
	}
};
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int x;
		cin >> x;
		CSieve c(x);
		c.printPrime();
	}
	return 0;
}

11.最胖的加菲(类与对象+数组)

题目描述

有一群猫猫,每只猫都有自己的名称和体重。

用类来描述猫,名称和体重都是私有属性,要求加入属性的get方法。其他函数根据需要自己定义

创建一个动态的猫对象数组,存储各只猫的名称和体重

根据猫的体重对数组做升序排序,并输出排序后每只猫的名称

题目涉及的数值均用整数处理

输入

第一行输入n表示有n只猫

第二行输入一只猫的名称和体重

依次输入n行

输出

输出一行,输出排序后的猫的名称

输入样例

4
chocolate 1500
water 400
cheese 3000
vegetable 200

输出样例

vegetable water chocolate cheese

AC代码

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
class Cat
{
private:
	string name;
	int weight;
public:
	void getcat(string Name, int Weight)
	{
        //因为是对象数组,而且各个对象赋值不同,直接用get进行赋值,比构造更方便
		name = Name;
		weight = Weight;
	}
	int getweight()
	{
		return weight;
	}
	string getname()
	{
		return name;
	}
};
//sort的时候保证是根据体重升序的
bool cmp(Cat& a, Cat& b)
{
	return a.getweight() < b.getweight();
}
//引用保证对主函数中的数据直接修改
void sortcat(Cat*& acat, int n)
{
	sort(acat, acat + n, cmp);
}
//Cat*acat相当于一个calss Cat类型的数组(注意*在&之前,因为&acat表引用acat)
void print(Cat*& acat, int n)
{
	for (int i = 0; i < n; i++)
	{
		cout << acat[i].getname();
		if (i == n - 1)cout << endl;
		cout << " ";
	}
}
int main()
{
	int n;
	cin >> n;
	Cat* acat = new Cat[n];//开一个calss Cat类型的数组
	for (int i = 0; i < n; i++)
	{
		string Name;
		int Weight;
		cin >> Name >> Weight;
		acat[i].getcat(Name, Weight);//一一赋值
	}
	sortcat(acat, n);
	print(acat, n);
	delete[]acat;//每次用new都要记得delete
	return 0;
}

12.【程序填空】日期比较(构造与析构)

题目描述

下面是一个日期类的定义,请在类外实现它的函数,

在主函数中先创建一个默认日期对象(无参构造)

然后输入一个日期数据年月日,创建一个日期对象(有参构造)

把输入的日期和默认日期进行比较,调用方法Before,根据比较结果输出相应的信息

注意:

凡是带"*********** constructed"的信息必定是由构造函数输出的信息

凡是带"*********** destructed"的信息必定是由析构函数输出的信息

不能在主函数或者其他区域显式地输出这些信息

输入

测试数据的组数t

输入t行年月日

输出

看样例

输入样例

3
2021 8 8
2023 1 1
2022 6 30

输出样例

Date 2022-4-1 default constructed
Date 2021-8-8 constructed
2021-8-8 before 2022-4-1
Date 2021-8-8 destructed
Date 2023-1-1 constructed
2022-4-1 before 2023-1-1
Date 2023-1-1 destructed
Date 2022-6-30 constructed
2022-4-1 before 2022-6-30
Date 2022-6-30 destructed
Date 2022-4-1 destructed
AC代码

//头文件和类声明
#include <iostream>
using namespace std;

class MyDate {
private:
	int year;
	int month;
	int day;
public:
	MyDate(); //无参构造,默认日期2022-4-1,输出相关构造信息
	MyDate(int ty, int tm, int td); //有参构造,根据参数初始化,输出相关构造信息
	~MyDate();
	bool Before(MyDate& rd);
	void print()
	{
		cout << year << "-" << month << "-" << day;
	}
};
//下面填写类实现和主函数
/********** Write your code here! **********/
MyDate::MyDate()
{
	year = 2022;
	month = 4;
	day = 1;
	cout << "Date ";
	print();
	cout << " default constructed" << endl;
}
MyDate::MyDate(int ty, int tm, int td)
{
	year = ty;
	month = tm;
	day = td;
	cout << "Date ";
	print();
	cout << " constructed" << endl;
}
bool MyDate::Before(MyDate& rd)
{
	if (rd.year < year)
	{
		return true;
	}
	else if (rd.year == year && rd.month < month)
	{
		return true;
	}
	else if (rd.year == year && rd.month == month && rd.day < day)
	{
		return true;
	}
	return false;
}
MyDate::~MyDate()
{
	cout << "Date ";
	print();
	cout << " destructed" << endl;
}
int main()
{
	int t;
	cin >> t;
	MyDate one;
	while (t--)
	{
		int yy, mm, dd;
		cin >> yy >> mm >> dd;
		MyDate two(yy, mm, dd);
		if (one.Before(two))
		{
			two.print();
			cout << " before ";
			one.print();
			cout << endl;
		}
		else
		{
			one.print();
			cout << " before ";
			two.print();
			cout << endl;
		}
	}
	return 0;
}
/*******************************************/
//main end 

13.最长雪道计算(构造与析构)(难)

题目描述

Michael喜欢滑雪, 因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael想知道载一个区域中最长底滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。

下面是一个例子

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

一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。

定义CSnowPath类,包含私有数据int n,m纪录二维数组大小,int **SnowH;动态分配,存储二维数组。公有函数int GetLongestValue()計算二维区域中最长度滑坡。为实现GetLongestValue(),可以增加其它需要的成员。

要求析构函数释放空间。

输入

第一行:二维区域的行数,列数n

第二行到第n+1行,二维数组,每个数字代表该点高度。

输出

最长雪道的长度

最长雪道路径上的高度值

输入样例


1  2  3  15 
10 11 12 13 
7  9  6  5  
1  3  4  2  

输出样例

9
15-13-12-11-9-6-4-3-1-

AC代码

#include<iostream>
#include<vector>
using namespace std;
static int q = 0;//记录路径时作为雪道长度,不断减少
static int t = 0;//记录路径时作为到达的点数,不断增加
class CSnowPath
{
private:
	int n;//二维数组大小
	int**snowh;//记录每个点的高度
	int length;//最长雪道长度
	int dx[4] = { 0,1,0,-1 };//dp偏移
	int dy[4] = { 1,0,-1,0 };//dp偏移
	int** f;//dp数组,记录到达每个点(每个点作为最高起始点)的最长雪道长度
	int* way;//记录最长雪道路径
	int px, py;//记录最长雪道最高起始点的那个点
public:
	CSnowPath(int nn,int **p)
	{
		n = nn;
		snowh = new int* [n];
		f = new int* [n];//动态数组初始为-1
		way = new int [n*n];//路径初始为0
		for (int i = 0; i < n * n; i++)
		{
			way[i] = 0;
		}
		for (int i = 0; i < n; i++)
		{
			snowh[i] = new int[n];
			f[i] = new int[n];
			for (int j = 0; j < n; j++)
			{
				snowh[i][j] = p[i][j];
				f[i][j] = -1;
			}
		}
		length = 0;//最长雪道长度初始为0
	}
	void GetLongest();
	int dp(int x, int y);
	void getpath(int x,int y);
	~CSnowPath()
	{
		for (int i = 0; i < n; i++)
		{
			delete[]snowh[i];
			delete[]f[i];
		}
		delete[]snowh;
		delete[]f;
		delete[]way;
	}
};
int CSnowPath::dp(int x, int y)
{
	if (f[x][y] != -1)//代表这个点已经走过了
		return f[x][y];
	int ans = 0;
	for (int i = 0; i < 4; i++)
	{
		int xx = x + dx[i];
		int yy = y + dy[i];
		if (xx >= 0 && xx <= n - 1 && yy >= 0 && yy <= n - 1 && snowh[x][y] > snowh[xx][yy])
		{
			ans = max(ans, dp(xx, yy));
		}
	}
	f[x][y] = ans + 1;//从xy的上下左右四个哪个大,再到x,y点,类似从最低到最高
	return f[x][y];//记得返回得到的值
}
void CSnowPath::GetLongest()
{
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (dp(i,j) > length)
			{
				length = f[i][j];
				px = i;
				py = j;
			}
		}
	}
	way[0] = snowh[px][py];//最长雪道起始点
	q = length - 1;
	getpath(px, py);
	cout << length << endl;
	for (int i = 0; i < length; i++)
	{
		cout << way[i] << "-";
	}
}
void CSnowPath::getpath(int x,int y)
{
    //类似为dp的逆过程,不过要记得记录当前雪道长度,且不断减少,因为是最长雪道长度,所以每个f[i][j]都是以(i,j)这个点为起始最高点的最长雪道长度,而逆过程保证了上一个点的高度一定高于下一个点,故可以用f[xx][yy]==q
	for (int i = 0; i < 4; i++)
	{
		int xx = dx[i] + x;
		int yy = dy[i] + y;
		if (xx >= 0 && xx <= n - 1 && yy >= 0 && yy <= n - 1 && snowh[x][y] > snowh[xx][yy]&&f[xx][yy] == q)
		{
			t++;
			way[t] = snowh[xx][yy];
			q--;
			//cout << t << " " << way[t] << " " << snowh[xx][yy] << " " << q << endl;
			getpath(xx, yy);
		}
	}
}
int main()
{
	int n;
	cin >> n;
	int** pp = new int* [n];
	for (int i = 0; i < n; i++)
	{
		pp[i] = new int[n];
		for (int j = 0; j < n; j++)
		{
			cin >> pp[i][j];
		}
	}
	CSnowPath c(n, pp);
	c.GetLongest();
    for(int i=0;i<n;i++)
    {
       delete[]pp[i];
    }
    delete[]pp;
    return 0;
}

14.单词逆序输出(类构造与析构)(难)

题目描述

试定义一个类 STR,将一个字符串中的各英文单词逆序处理(已知英文单词之间以非英文字母分隔)。

具体要求如下:

(1)私有数据成员

 char *s:指向待处理的字符串。

(2)公有成员函数

 STR (char *t) :构造函数,根据 t 参数初始化数据成员 s。

 void backward (char *t1,char *t2) :将指针 t1、t2 之间的字符前后逆序。

 void fun( ) :按题意利用函数 backward()将字符串 s 中的各英文单词逆序。

 void print():输出数据成员。

 ~STR();析构函数,实现必要的功能

输入

输入需要处理的字符串

输出

输出处理后的字符串

输入样例

I ma a tneduts

输出样例

I am a student

AC代码

#include <iostream>
#include <cstring>
#include<sstream>//getline需要
using namespace std;
class STR
{
    char* s;
public:
    STR(char* t) {
        s = new char[strlen(t) + 1];
        for (int i = 0; i <= strlen(t); i++)//包括字符串结尾符
        {
            s[i] = t[i];
        }
    }
    void backward(char* t1, char* t2) {
        while (t1 < t2)//当左指针指向的下标小于右指针时进行,进行交换,左指针右移,右指针左移
        {
            char t = *t1;
            *t1++ = *t2;
            *t2-- = t;
        }
    }
    int Alph(char c) //判断是否为英文字符(英文字符才需要逆转)
    {
        if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')return 1;
        else return 0;
    }
    void fun() {
        char* p = s, * p2;//p从字符串头到尾
        while (*p)//当P不指向空,也就是到达最后一个之后就不会进入while了
        {
            p2 = p;
            while (Alph(*p2)) {
                p2++;
            }
            //找到一个单词,p2要减一,因为while里加一了
            backward(p, p2 - 1);
            p = p2 + 1;//之后p移动到单词的下一个字符
        }
    }
    void print() {
        cout << s << endl;
    }
    ~STR()
    {
        if (s)//不是空指针
            delete[]s;
    }
};
int main()
{
    string t;
    getline(cin, t);//输入带有空格的字符串
    char* s;
    s = new char[t.size() + 1];
    for (int i = 0; i < t.size(); i++)
    {
        s[i] = t[i];
    }
    s[t.size()] = '\0';//记得字符串结尾符
    STR str(s);
    str.fun();
    str.print();
    return 0;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值