id:31 A.Point(类与构造)
题目描述
下面是一个平面上的点的类定义,请在类外实现它的所有方法,并生成点测试它。
class Point
{
double x, y;
public:
Point(); // 缺省构造函数,给x,y分别赋值为0
Point(double x_value, double y_value); // 有参构造函数
double getX(); // 返回x的值
double getY();
void setX(double x_value); // 设置x的值
void setY(double y_value);
double dis(Point p); // 计算当前点到参数点的距离
};
输入
测试数据的组数 t
第一组测试数据点p1的x坐标 第一组测试数据点p1的y坐标 第一组测试数据点p2的x坐标 第一组测试数据点p2的y坐标
…
输出
输出p1到p2的距离,保留两位小数。详情参考输出样例。
在C++中,输出指定精度的参考代码如下:
#include <iostream>
#include <iomanip> //必须包含这个头文件
using namespace std;
void main( )
{ double a =3.14;
cout<<fixed<<setprecision(3)<<a<<endl; //输出小数点后3位
}
输入样例
2
1 2 3 4
-1 0.5 -2 5
输出样例
Distance of Point(1.00,2.00) to Point(3.00,4.00) is 2.83
Distance of Point(-1.00,0.50) to Point(-2.00,5.00) is 4.61
题解
- 首先分析
class
类,Point(); // 缺省构造函数,给x,y分别赋值为0
,这行代码的意思是,当使用Point类型定义一个变量且后面不跟任何参数时,会默认的执行这个函数,即为x, y分别赋值为0;Point(double x_value, double y_value); // 有参构造函数
,若用Point类型定义一个变量,且这个变量后面带参数,即会给这个变量的成员x和y赋括号里参数的值;double getX(); // 返回x的值
,当调用这个函数时,我们的目的是得到Point类型的变量的成员x的值;同理double getY();
这个代码的功能也是一样的;void setX(double x_value); // 设置x的值
,当调用这个函数时,会将调用这个函数的变量的x的值改变为参数的值;同理void setY(double y_value);
;double dis(Point p); // 计算当前点到参数点的距离
,在这个函数中,我们还要额外定义三个变量,一个用来存储两个点之间横坐标距离之差,一个用来存储纵坐标距离之差,还有一个用来存储计算得到的距离并返回,注意,在计算两个点之间的距离时,我们需要使用到两个点的横纵坐标的值,故会引起怎么引用的问题,我们需要用一个参数来调用这个计算两个点之间的距离的函数,故完成了一个点的调用,然后这个函数是带有参数的,把另一个点当作参数调用,则完成了两个点的调用,在这个函数中,x和y是调用这个函数的变量的成员,而怎么调用另一个变量的横纵坐标呢,则需要使用get函数,这个另一个点调用这个函数,然后会返回这个变量的横纵坐标,则实现了两个点的横纵坐标的调用 - 然后来看主函数的功能,在主函数中,我们需要定义测试组数和遍历变量,一个用于接收返回距离两点间答案的变量,然后定义一个Point类型的变量,这个变量会执行一次缺省构造函数,还要定义四个变量用于接收输入进来的两个点的横纵坐标的值
- 一个for循环,遍历完全组的两点,输入两个点的横纵坐标,然后定义一个Point类型的变量,带两个参数,将这两个参数的值赋到这个变量的横纵坐标变量,再调用类里边的set函数,将另外两个横纵坐标赋值到这个调用的变量的横纵坐标变量上,为什么要怎么麻烦,我也不懂,因为题目要求用上所有的类里边的函数,只能这样
- 最后就是按着输出样例的格式输出距离
代码实现
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
class Point
{
double x, y;
public:
Point(); // 缺省构造函数,给x,y分别赋值为0
Point(double x_value, double y_value); // 有参构造函数
double getX(); // 返回x的值
double getY();
void setX(double x_value); // 设置x的值
void setY(double y_value);
double dis(Point p); // 计算当前点到参数点的距离
};
Point::Point()
{
x = 0;
y = 0;
}
Point::Point(double x_value, double y_value)
{
x = x_value;
y = y_value;
}
double Point::getX()
{
return x;
}
double Point::getY()
{
return y;
}
void Point::setX(double x_value)
{
x = x_value;
}
void Point::setY(double y_value)
{
y = y_value;
}
double Point::dis(Point p)
{
double result, dx, dy;
dx = x - p.getX();
dy = y - p.getY();
result = sqrt(dx * dx + dy * dy);
return result;
}
int main()
{
int t, i;
double ans, p1x, p1y, p2x, p2y;
Point p2;
cin >> t;
for (i = 0; i < t; i++)
{
cin >> p1x >> p1y >> p2x >> p2y;
Point p1(p1x, p1y);
p2.setX(p2x);
p2.setY(p2y);
ans = p1.dis(p2);
cout << "Distance of Point(" << fixed << setprecision(2) << p1.getX() << "," << fixed << setprecision(2) << p1.getY() << ") to Point(" << fixed << setprecision(2) << p2.getX() << "," << fixed << setprecision(2)<< p2.getY() << ") is ";
cout << fixed << setprecision(2) << ans << endl;
}
return 0;
}
id:32 B.Date(类与构造)
题目描述
下面是一个日期类的定义,请在类外实现其所有的方法,并在主函数中生成对象测试之。
class Date
{
int year, month, day;
public:
Date(); // 缺省构造函数
Date(int y, int m, int d); // 带参构造函数
int getYear(); // 返回当前日期的年份
int getMonth();
int getDay();
void setDate(int y, int m, int d); // 按参数重设日期的值
void print(); // 按格式输出当前日期的年、月、日
void addOneDay(); // 在当前日期上加一天
};
注意,在判断明天日期时,要加入跨月、跨年、闰年的判断
例如9.月30日的明天是10月1日,12月31日的明天是第二年的1月1日
2月28日的明天要区分是否闰年,闰年则是2月29日,非闰年则是3月1日
输入
测试数据的组数t
第一组测试数据的年 月 日
…
要求第一个日期的年月日初始化采用构造函数,第二个日期的年月日初始化采用setDate方法,第三个日期又采用构造函数,第四个日期又采用setDate方法,以此类推。
输出
输出今天的日期
输出明天的日期
输入样例1
4
2012 1 3
2012 2 28
2012 3 31
2012 4 30
输出样例1
Today is 2012/01/03
Tomorrow is 2012/01/04
Today is 2012/02/28
Tomorrow is 2012/02/29
Today is 2012/03/31
Tomorrow is 2012/04/01
Today is 2012/04/30
Tomorrow is 2012/05/01
输入样例2
4
2014 1 3
2014 2 28
2014 3 31
2014 4 30
输入样例3
3
2000 2 29
2014 3 31
2014 12 31
提示
C++中设置填充字符的代码参考如下:
cout << setfill('0') << setw(2) << month; //设置宽度为2,前面补'0'
需要头文件#include <iomanip>
题解
- 首先来分析日期类,
Date(); // 缺省构造函数
,用来初始化类里面的年月日;Date(int y, int m, int d); // 带参构造函数
,用来给年月日赋参数的值,int getYear(); // 返回当前日期的年份
,通过调用这个函数,我们可以得到调用这个函数的变量的年份的值;同理int getMonth();
int getDay();
这两行的代码功能相同;void setDate(int y, int m, int d); // 按参数重设日期的值
将日期的值设为参数的值,这个函数可以用在初始化一个Date类型的变量中;void print(); // 按格式输出当前日期的年、月、日
,这个函数只用于输出当天日期的值,即,当输入一个日期时,便马上调用这个函数输出这个日期的值;void addOneDay(); // 在当前日期上加一天
,这个函数用来计算输入的日期的下一天的日期 void addOneDay(); // 在当前日期上加一天
,在这个函数中,我们先用日作为if语句判断的条件,然后再判断月份,最后判断年份;具体来数,我们把判断的条件划分为,是否是28号,29号,30号和31号这几个特殊的日期,如果是28号的话,再判断其是否是2月份,再判断其是否是闰年,如果是29号的话,判断其是否是二月份,但是不用再判断是否是闰年,如果是30号的话,要分大小月;31号特殊的地方在于要判断他的月份是否是12月,如果是的话要年份加一- 然后来看看主函数的功能,需要定义用于存储输入进来的年月日的变量,然后还要定义Date类型的变量,因为需要年月日的成员,在定义这个变量是,程序自动地执行缺省构造函数
- 然后进行输入,因为题目有要求,所以需要根据不同的输入次数采用不同的方法初始化变量,当输入的次数为奇数次时,采用带参构造函数法,因为此时已经输入了年月日,要把输入进来的年月日传入变量中,随即调用输出函数输出当前的日期,然后调用日期加一函数,计算加一后的日期,然后在主函数中输出加了一天后的日期;如果输入次数为偶数次时,日期的初始化采用setDate方法,即调用这个函数初始化变量,后面的步骤相同
代码实现
#include <iostream>
#include <iomanip>
using namespace std;
class Date
{
int year, month, day;
public:
Date(); // 缺省构造函数
Date(int y, int m, int d); // 带参构造函数
int getYear(); // 返回当前日期的年份
int getMonth();
int getDay();
void setDate(int y, int m, int d); // 按参数重设日期的值
void print(); // 按格式输出当前日期的年、月、日
void addOneDay(); // 在当前日期上加一天
};
Date::Date()
{
year = 1900;
month = 1;
day = 1;
}
Date::Date(int y, int m, int d)
{
year = y;
month = m;
day = d;
}
int Date::getYear()
{
return year;
}
int Date::getMonth()
{
return month;
}
int Date::getDay()
{
return day;
}
void Date::setDate(int y, int m, int d)
{
year = y;
month = m;
day = d;
}
void Date::print()
{
cout << "Today is " << setfill('0') << setw(2) << year << "/" << setfill('0') << setw(2) << month << "/" << setfill('0') << setw(2) << day << endl;
}
void Date::addOneDay()
{
if (day == 28)
{
if (month == 2)
{
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) // 是闰年
{
day++;
}
else // 不是闰年
{
day = 1;
month++;
}
}
}
else if (day == 29)
{
if (month == 2)
{
day = 1;
month++;
}
else
{
day++;
}
}
else if (day == 30)
{
switch (month)
{
case 1: day++;
break;
case 3: day++;
break;
case 4: day = 1;
month++;
break;
case 5: day++;
break;
case 6: day = 1;
month++;
break;
case 7: day++;
break;
case 8: day++;
break;
case 9: day = 1;
month++;
break;
case 10: day++;
break;
case 11: day = 1;
month++;
break;
case 12: day++;
break;
}
}
else if (day == 31)
{
if (month == 12)
{
day = 1;
year++;
month = 1;
}
else
{
day = 1;
month++;
}
}
else
{
day++;
}
}
int main()
{
int t, i, yy, mm, dd;;
Date DD;
cin >> t;
for (i = 0; i < t; i++)
{
cin >> yy >> mm >> dd;
if (i % 2 == 0)
{
Date DD0(yy, mm, dd);
DD0.print();
DD0.addOneDay();
cout << "Tomorrow is " << setfill('0') << setw(2) << DD0.getYear() << "/" << setfill('0') << setw(2) << DD0.getMonth() << "/" << setfill('0') << setw(2) << DD0.getDay() << endl;
}
else
{
DD.setDate(yy, mm, dd);
DD.print();
DD.addOneDay();
cout << "Tomorrow is " << setfill('0') << setw(2) << DD.getYear() << "/" << setfill('0') << setw(2) << DD.getMonth() << "/" << setfill('0') << setw(2) << DD.getDay() << endl;
}
}
return 0;
}
id:33 C.分数类(类与构造)
题目描述
完成下列分数类的实现:
class CFraction
{
private:
int fz, fm;
public:
CFraction(int fz_val, int fm_val) ;
CFraction add(const CFraction &r);
CFraction sub(const CFraction &r);
CFraction mul(const CFraction &r);
CFraction div(const CFraction &r);
int getGCD(); // 求对象的分子和分母的最大公约数
void print();
};
求两数a、b的最大公约数可采用辗转相除法,又称欧几里得算法,其步骤为:
- 交换a, b使a > b;
- 用a除b得到余数r,若r=0,则b为最大公约数,退出.
- 若r不为0,则用b代替a, r代替b,此时a,b都比上一次的小,问题规模缩小了;
- 继续第2步。
注意:如果分母是1的话,也按“分子/1”的方式输出。
输入
测试数据的组数 t
第一组第一个分数
第一组第二个分数
第二组第一个分数
第二组第二个分数
…
输出
第一组两个分数的和
第一组两个分数的差
第一组两个分数的积
第一组两个分数的商
第二组两个分数的和
第二组两个分数的差
第二组两个分数的积
第二组两个分数的商
…
输入样例
3
1/2
2/3
3/4
5/8
21/23
8/13
输出样例
7/6
-1/6
1/3
3/4
11/8
1/8
15/32
6/5
457/299
89/299
168/299
273/184
题解
- 首先来看
CFraction
类,CFraction(); // 缺省构造函数
,将fz和fm都赋值为1;CFraction(int fz_val, int fm_val); // 带参构造函数
,将fz和fm都赋值为参数的值;CFraction add(const CFraction& r);
,在这个函数中,要定义整形三个变量,一个用来将分子相加得到的结果存储,一个将新得到的分母进行存储,还要定义一个CFraction类型的变量,定义时要含参,参数即是新的分子分母,这个变量的分子和分母即是得到的新的分子和分母,然后这个新定义的变量调用求最大公约数的函数,将得到的最大公约数的值存储到一个整型变量中,然后更新分子和分母,即是分子和分母约分后的值,再定义一个CFraction
类型的变量,也要含参,参数就是更新后的分子分母,作用就是,将参数赋值给这个变量的分子分母,故这个变量就是两个分数相加的结果,返回最后定义的这个CFraction
类型的变量;后面的和差积商都是相同的方法;int getGCD(); // 求对象的分子和分母的最大公约数
,用到的方法是辗转相除法,需要注意的是,如果出现了负数,我们需要确保这个计算得到的最大公约数的结果,及返回值是正数,所以我们需要判断参数进来的是否是正数;void print();
,进行简单的输出即可 - 在主函数中,我们需要定义四个整型变量,用来存储输入进来的两个分数的分子和分母,还要定义一个char型的变量,用来存储"/",输入两个分数的分子和分母后,定义两个
CFraction
类型的变量,后面带两个参数,即是要赋值到这个变量的分子和分母的参数,还要定义一个CFraction
类型的变量,这个变量用来存储计算后返回的结果,然后这个变量调用输出函数进行计算后得到的结果进行输出,每做完一个计算就调用一次输出函数进行输出
反思
在类函数的实现时,如两个分数的相加,一开始我没有额外的定义一个整形变量来存储计算后的分子分母的值,而是将计算后的值直接更新到调用这个加法函数的变量的分子上,导致后来这个分数的分子已经不是原来输入的分子,即他的值已经改变,所以后面再进行的减法,乘法和除法得到的结果都是错的
代码实现
#include <iostream>
using namespace std;
class CFraction
{
private:
int fz, fm;
public:
CFraction(); // 缺省构造函数
CFraction(int fz_val, int fm_val); // 带参构造函数
CFraction add(const CFraction& r);
CFraction sub(const CFraction& r);
CFraction mul(const CFraction& r);
CFraction div(const CFraction& r);
int getGCD(); // 求对象的分子和分母的最大公约数
void print();
};
CFraction::CFraction()
{
fz = 1;
fm = 1;
}
CFraction::CFraction(int fz_val, int fm_val)
{
fz = fz_val;
fm = fm_val;
}
CFraction CFraction::add(const CFraction& r)
{
int new_fz, new_fm, gcd;
new_fz = fz * r.fm + r.fz * fm;
new_fm = fm * r.fm;
CFraction f(new_fz, new_fm);
gcd = f.getGCD();
new_fz /= gcd;
new_fm /= gcd;
CFraction ff(new_fz, new_fm);
return ff;
}
CFraction CFraction::sub(const CFraction& r)
{
int new_fz, new_fm, gcd;
new_fz = fz * r.fm - r.fz * fm;
new_fm = fm * r.fm;
CFraction f(new_fz, new_fm);
gcd = f.getGCD();
new_fz /= gcd;
new_fm /= gcd;
CFraction ff(new_fz, new_fm);
return ff;
}
CFraction CFraction::mul(const CFraction& r)
{
int new_fz, new_fm, gcd;
new_fz = fz * r.fz;
new_fm = fm * r.fm;
CFraction f(new_fz, new_fm);
gcd = f.getGCD();
new_fz /= gcd;
new_fm /= gcd;
CFraction ff(new_fz, new_fm);
return ff;
}
CFraction CFraction::div(const CFraction& r)
{
int new_fz, new_fm, gcd;
new_fz = fz * r.fm;
new_fm = fm * r.fz;
CFraction f(new_fz, new_fm);
gcd = f.getGCD();
new_fz /= gcd;
new_fm /= gcd;
CFraction ff(new_fz, new_fm);
return ff;
}
int CFraction::getGCD()
{
int a, b, r, x;
a = fm;
b = fz;
if (b < 0)
{
b = -b;
}
if (a < b) // 确保a > b
{
x = a;
a = b;
b = x;
}
r = a % b;
while (r != 0)
{
a = b;
b = r;
r = a % b; // r为余数
}
return b;
}
void CFraction::print()
{
cout << fz << "/" << fm << endl;
}
int main()
{
int t, i, x1, x2, y1, y2;
char ch;
cin >> t;
for (i = 0; i < t; i++)
{
cin >> x1 >> ch >> x2 >> y1 >> ch >> y2;
CFraction x(x1, x2);
CFraction y(y1, y2);
CFraction result;
result = x.add(y);
result.print();
result = x.sub(y);
result.print();
result = x.mul(y);
result.print();
result = x.div(y);
result.print();
cout << endl;
}
return 0;
}
id:34 D.Point_Array(类+构造+对象数组)
题目描述
上面是我们曾经练习过的一个习题,请在原来代码的基础上作以下修改:
1、增加自写的析构函数;
2、将getDisTo方法的参数修改为getDisTo(const Point &p);
3、根据输出的内容修改相应的构造函数。
然后在主函数中根据用户输入的数目建立Point数组,求出数组内距离最大的两个点之间的距离值。
输入
测试数据的组数 t
第一组点的个数
第一个点的 x 坐标 y坐标
第二个点的 x坐标 y坐标
…
输出
输出每组中距离最大的两个点以及其距离(存在多个距离都是最大值的情况下,输出下标排序最前的点组合。比如如果p[0]和p[9]、p[4]和p[5]之间的距离都是最大值,那么前一个是答案,因为p[0]排序最前)
…
在C++中,输出指定精度的参考代码如下:
#include
#include //必须包含这个头文件
using namespace std;
void main( )
{ double a =3.141596;
cout<<fixed<<setprecision(3)<<a<<endl; //输出小数点后3位
输入样例
2
4
0 0
5 0
5 5
2 10
3
-1 -8
0 9
5 0
输出样例
Constructor.
Constructor.
Constructor.
Constructor.
The longest distance is 10.44,between p[1] and p[3].
Distructor.
Distructor.
Distructor.
Distructor.
Constructor.
Constructor.
Constructor.
The longest distance is 17.03,between p[0] and p[1].
Distructor.
Distructor.
Distructor.
题解
- 首先分析类,
Point(); // 缺省构造函数,输出
,因为看到输出样例中,每输入一个点的横纵坐标都伴随着一个Constructor.
的输出,故可以知道,这个缺省构造函数的作用是输出Constructor.
;Point(double x_value, double y_value); // 有参构造函数,给x,y赋参数的值
,这个构造函数的作用是把调用这个变量的横纵坐标的值改变为参数的值;~Point(); // 析构函数,输出
,同理,观察到每输入一个横纵坐标的值,都会伴随着Distructor.
的输出,且这个输出在输出了距离之后才输出;double getX(); // 返回x的值
,作用是当在调用这个函数时,返回横坐标的值,即是当我们需要这个变量的横坐标时,我们就可以调用这个函数;double getY();
,同理;void setXY(double x1, double y1); // 赋参数的值
,当调用这个函数时,这个函数就会改变横纵坐标的值为参数的值;void setX(double x_value); // 设置x的值
,当在调用这个函数时,这个变量的横坐标就会变为参数的值;void setY(double y_value);
,同理;double getDisTo(const Point& p); // 计算当前点到参数p的距离
,在这个函数中,我们首先要定义三个变量,一个用来存储两个点横坐标之差,横坐标之差的计算是,直接用调用这个函数的横坐标的值减去参数的横坐标的值,怎么得到参数的横坐标的值呢,因为参数也是一个Point
类型的变量,所以我们可以使用”."来访问它的成员,即是它的横坐标的值,另一个变量用来存储纵坐标之差,还有一个变量用来存储计算得到的两点之间的距离,并返回 - 然后来看主函数的作用,因为我们要比较两个点的距离,而我们又会输入多个不同的点,所以我们会考虑用一个
Point
类型的数组来存储这些点的信息,题目有要求用动态创建的方法,所以我们采用new
的方法,注意,使用后要释放内存,我们还要创建变量来存储输入进来的横纵坐标的值,这些值输入进来后我们要将他们赋值到到点的横纵坐标中,所以这时我们调用void setXY(double x1, double y1)
函数 - 然后我们编写计算两个点之间的距离的代码,我们可以使用两个嵌套的for循环,达到逐个遍历两个点,然后调用距离计算函数返回这两个点的距离,在用这个返回值与当前最大值进行比较,再进行更新和记录此时的横纵坐标的值的操作
- 最后就是进行一些简单的输出
疑问
- 为什么这段代码
double Point::getDisTo(const Point& p)
{
double result, dx, dy;
dx = x - p.x;
dy = y - p.y;
result = sqrt(dx * dx + dy * dy);
return result;
}
不能写成
double Point::getDisTo(const Point& p)
{
double result, dx, dy;
dx = x - p.getX();
dy = y - p.getY();
result = sqrt(dx * dx + dy * dy);
return result;
}
代码实现
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
class Point
{
double x, y;
public:
Point(); // 缺省构造函数,输出
Point(double x_value, double y_value); // 有参构造函数,给x,y赋参数的值
~Point(); // 析构函数,输出
double getX(); // 返回x的值
double getY();
void setXY(double x1, double y1); // 赋参数的值
void setX(double x_value); // 设置x的值
void setY(double y_value);
double getDisTo(const Point& p); // 计算当前点到参数p的距离
};
Point::Point()
{
cout << "Constructor." << endl;
}
Point::Point(double x_value, double y_value)
{
x = x_value;
y = y_value;
}
Point::~Point()
{
cout << "Distructor." << endl;
}
double Point::getX()
{
return x;
}
double Point::getY()
{
return y;
}
void Point::setXY(double x1, double y1) // 赋参数的值
{
x = x1;
y = y1;
}
void Point::setX(double x_value)
{
x = x_value;
}
void Point::setY(double y_value)
{
y = y_value;
}
double Point::getDisTo(const Point& p)
{
double result, dx, dy;
dx = x - p.x; // 疑问
dy = y - p.y;
result = sqrt(dx * dx + dy * dy);
return result;
}
int main()
{
int t, i, n, j, k, x, y;
double x1, y1, max, dis;
cin >> t; // 组数
for (i = 0; i < t; i++)
{
max = 0;
dis = 0;
cin >> n; // 点的个数
Point* pp = new Point[n]; // 动态创建数组
for (j = 0; j < n; j++)
{
cin >> x1 >> y1; // 横纵坐标的值
pp[j].setXY(x1, y1); // 赋参数的值
}
for (j = 0; j < n; j++) // 计算两个点之间的距离
{
for (k = j + 1; k < n; k++)
{
dis = pp[j].getDisTo(pp[k]);
if (max < dis)
{
max = dis; // 更新
x = j; // 记录横纵坐标
y = k;
}
}
}
cout << "The longest distance is " << fixed << setprecision(2) << max;
cout << ",between p[" << x << "]" << " and p[" << y << "]." << endl;
delete[] pp; // 释放内存
}
return 0;
}
id:35 E.Stack(类与构造)
题目描述
class CStack
{
public:
CStack(); // 建立一个10个元素的栈
CStack(int s); // 建立一个具有s个元素的栈
int get(int index); // 返回下标为index的栈元素
void push(int n); // 进栈,top加1,把n的值存入栈顶
int isEmpty(); // 判断栈否是空的,空则返回一,否则返回0
int isFull(); // 判断栈是否是满的,满则返回1,否则返回0
int pop(); // 出栈,返回栈顶元素,top减1
~CStack(); // 析构函数,释放在构造时申请的空间
private:
int* a;
int size; // 栈的大小
int top; // 指向栈顶
};
上面是栈类的定义,栈是一种具有先进后出特点的线性表,请根据注释,完成类中所有方法的实现,并在主函数中测试之。
堆栈类的说明如下:
-
堆栈的数据实际上是保存在数组a中,而a开始是一个指针,在初始化时,根据实际需求将a动态创建为数组,数组长度根据构造函数的参数决定。
-
size实际上就是数组的长度,当使用无参构造则size为10,当使用有参构造则size为s、
-
top表示数组下标,也表示数组中下一个存放数据的空白位置。
-
push操作表示堆栈的数组存放一个数据,例如一开始数组为空,则top为0,当有数据要入栈时,把数据存放在a[top]的位置,然后top加1指向下一个空白位置、数据进栈只能从栈顶进。
-
pop操作表示一个数据要出栈,数据出栈只能从栈顶出,先把top减1指向栈顶数据,然后把数据返回。
-
判断堆栈空的条件是top是否等于0,判断堆栈满的条件是top是否等于size
输入
测试数据的组数 t
第一个栈的大小
第一个栈的元素列表,将该列表的元素依次进栈
…
输出
将栈元素依次出栈
输入样例
2
5
1 2 3 4 5
7
-1 2 8 0 -3 1 3
输出样例
Constructor.
5 4 3 2 1
Destructor.
Constructor.
3 1 -3 0 8 2 -1
Destructor.
题解
- 首先来解释类,即栈的建立,
CStack(); // 建立一个10个元素的栈
,在这个函数中,我们要实现将栈的大小,及数组的大小设置为10,然后我们还要动态创建一个数组,即a,还要将top
,及记录指向数组的一个整形变量,就是数组的下标初始化为0,即指向第一个位置,那为什么我们要在构造函数中动态创建一个数组和初始化一个变量的值呢,因为我们这个数组已经在类中定义好了,而不是在主函数中定义好的,我们主要的操作就是对这个数组进行操作,而在主函数中我们定义一个CStack
类型的变量的作用是调用这些对栈进行的操作的函数,所以最先会调用到这个构造函数,所以我们在一开始就要动态创建数组和初始化变量;CStack(int s); // 建立一个具有s个元素的栈
,这也是一个构造函数,所以我们在将参数设置为栈的大小时还要动态创建数组和初始化变量,使得无论主函数调用了那个构造函数,数组都得以创建,变量得以初始化;int get(int index); // 返回下标为index的栈元素
,调用这个函数时我们会得到一个值,即下表为参数的数组元素的值;void push(int n); // 进栈,top加1,把n的值存入栈顶
,在这个函数中,我们把参数赋值给当前数组的空白位置,然后将数组的下标加一,使得可以存放下一次的值;int isEmpty(); // 判断栈否是空的,空则返回一,否则返回0
,题目有讲怎么判断;int isFull(); // 判断栈是否是满的,满则返回1,否则返回0
,同理;int pop(); // 出栈,返回栈顶元素,top减1
,出栈时表示数组下标的值要减一,然后把当前数组的元素返回,要先减一再返回值,因为前面的操作会使这个这个数组下标的变量指向了一个空的地方;~CStack(); // 析构函数,释放在构造时申请的空间
,释放空间和输出一句话 - 在主函数中,我们首先要定义一个
CStack
类型的变量,目的是把输入进来的栈的大小设置为类中数组的大小,然后把输入进去的值通过调用进栈函数进栈,然后通过判断栈是满的还是空的,还是其他的情况,通过调用出栈函数输出元素的值,主要是使得输出和样例相同
代码实现
#include <iostream>
using namespace std;
class CStack
{
public:
CStack(); // 建立一个10个元素的栈
CStack(int s); // 建立一个具有s个元素的栈
int get(int index); // 返回下标为index的栈元素
void push(int n); // 进栈,top加1,把n的值存入栈顶
int isEmpty(); // 判断栈否是空的,空则返回一,否则返回0
int isFull(); // 判断栈是否是满的,满则返回1,否则返回0
int pop(); // 出栈,返回栈顶元素,top减1
~CStack(); // 析构函数,释放在构造时申请的空间
private:
int* a;
int size; // 栈的大小
int top; // 指向栈顶
};
CStack::CStack()
{
size = 10;
a = new int[size]; // 分配内存空间
top = 0; // 初始化
cout << "Constructor." << endl;
}
CStack::CStack(int s)
{
size = s;
a = new int[size]; // 分配内存空间
top = 0; // 初始化
cout << "Constructor." << endl;
}
int CStack::get(int index)
{
return a[index];
}
void CStack::push(int n)
{
a[top] = n;
top++; // 指向下一个空白位置
}
int CStack::isEmpty()
{
if (top == 0) // 栈空
{
return 1;
}
return 0; // 不空
}
int CStack::isFull()
{
if (top == size) // 栈满
{
return 1;
}
return 0; // 不满
}
int CStack::pop()
{
top--; // 指向栈顶数据
return a[top]; // 把数据返回
}
CStack::~CStack()
{
cout << "Destructor." << endl;
delete[] a;
}
int main()
{
int t, i, n, j, x, result;
cin >> t; // 组数
for (i = 0; i < t; i++)
{
cin >> n; // 栈的大小
CStack aa(n);
for (j = 0; j < n; j++)
{
cin >> x;
aa.push(x); // 进栈
}
for (j = 0; j < n; j++)
{
if (aa.isFull()) // 如果栈是满的
{
result = aa.pop();
cout << result;
}
else if (aa.isEmpty()) // 如果栈是空的
{
result = aa.pop();
cout << result << endl;
}
else // 中间的元素
{
result = aa.pop();
cout << " " << result;
}
}
cout << endl;
}
return 0;
}