C++_第五周做题总结_构造与析构

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的最大公约数可采用辗转相除法,又称欧几里得算法,其步骤为:

  1. 交换a, b使a > b;
  2. 用a除b得到余数r,若r=0,则b为最大公约数,退出.
  3. 若r不为0,则用b代替a, r代替b,此时a,b都比上一次的小,问题规模缩小了;
  4. 继续第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; // 指向栈顶
};

上面是栈类的定义,栈是一种具有先进后出特点的线性表,请根据注释,完成类中所有方法的实现,并在主函数中测试之。

堆栈类的说明如下:

  1. 堆栈的数据实际上是保存在数组a中,而a开始是一个指针,在初始化时,根据实际需求将a动态创建为数组,数组长度根据构造函数的参数决定。

  2. size实际上就是数组的长度,当使用无参构造则size为10,当使用有参构造则size为s、

  3. top表示数组下标,也表示数组中下一个存放数据的空白位置。

  4. push操作表示堆栈的数组存放一个数据,例如一开始数组为空,则top为0,当有数据要入栈时,把数据存放在a[top]的位置,然后top加1指向下一个空白位置、数据进栈只能从栈顶进。

  5. pop操作表示一个数据要出栈,数据出栈只能从栈顶出,先把top减1指向栈顶数据,然后把数据返回。

  6. 判断堆栈空的条件是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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/546304.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

顶顶通呼叫中心中间件-SIP分机安全(mod_cti基于FreeSWITCH)

介绍 运行在公网的FreeSWITCH服务器&#xff0c;每天都会接收到很多恶意的呼叫请求和注册请求&#xff0c;尝试盗打电话。合理的配置可以防止电话给倒打&#xff0c;但是每天大量的攻击&#xff0c;会让FS产生很多日志&#xff0c;降低FreeSWITCH的处理能力&#xff0c;cti模块…

【Entity Framework】你要知道EF中功能序列与值转换

【Entity Framework】你要知道EF中功能序列与值转换 文章目录 【Entity Framework】你要知道EF中功能序列与值转换一、序列1.1 基本用法1.2 配置序列设置 二、值转换2.1 配置值转换器2.2 批量配置值转换器2.3 预定义的转换2.4 ValueConverter类2.5 内置转换器 三、应用3.1 简单…

C语言面试题之奇偶链表

奇偶链表 实例要求 1、给定单链表的头节点 head &#xff0c;将所有索引为奇数的节点和索引为偶数的节点分别组合在一起&#xff0c;然后返回重新排序的列表&#xff1b;2、第一个节点的索引被认为是 奇数 &#xff0c; 第二个节点的索引为 偶数 &#xff0c;以此类推&#x…

【Linux】Linux基础与常用指令大全

文章目录 操作系统是什么&#xff1f;1. Linux家族介绍2. Linux的安装方式3. 常用指令3.1 ls [选项] [目录/文件]&#xff08;显示目录或文件信息&#xff09;3.2 pwd&#xff08;显示当前所在目录&#xff09;3.3 任意指令加上 --help&#xff08;查看指令的用法&#xff09;3…

半导体材料(一)

本篇为西安交通大学本科课程《电气材料基础》的笔记。 本篇为这一单元的第一篇笔记&#xff0c;下一篇传送门。 半导体是导电能力介于均属导体和绝缘体之间的固体材料。 半导体基本特征 室温下其电阻数量级约为 1 0 − 6 ∼ 1 0 8 Ω ⋅ m 10^{-6}\sim10^{8}\mathrm{\Omega…

玩steam游戏提示缺少dll文件怎么办,总结5种解决方法

在尝试运行您所期待已久的Steam平台上的某款精彩游戏时&#xff0c;您可能遭遇了一个令人颇为困扰的问题&#xff1a;系统提示“Steam游戏缺少dll文件&#xff0c;游戏无法启动”。为了解决这个问题&#xff0c;我总结了以下五种解决方法&#xff0c;希望能帮助到遇到类似问题的…

用three.js做一个3D汉诺塔游戏(下)

本文由孟智强同学原创。 接上期&#xff1a;《用three.js做一个3D汉诺塔游戏&#xff08;上&#xff09;》 在上一期&#xff0c;我们成功地搭建了基础的 3D 场景。在本期中&#xff0c;我们将对场景进行优化&#xff0c;使其在视觉上更加真实&#xff0c;并为场景中的物体添加…

【数据结构】【C++】AVL树的模拟实现(插入、判断、旋转)

文章目录 1 概念2 实现2.1 AVL树结点的定义2.2 AVL树的插入2.2.1 AVL树的插入规则2.2.2 旋转2.2.2.1 左单旋2.2.2.2 右单旋2.2.2.3 左右双旋2.2.2.4 右左双旋 2.2.3 总结 3 平衡判断4 删除5 源码 1 概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二…

论文速读:Do Generated Data Always Help Contrastive Learning?

在对比学习领域&#xff0c;最近很多研究利用高质量生成模型来提升对比学习 给定一个未标记的数据集&#xff0c;在其上训练一个生成模型来生成大量的合成样本&#xff0c;然后在真实数据和生成数据的组合上执行对比学习这种使用生成数据的最简单方式被称为“数据膨胀”这与数据…

案例三 BeautifulSoup之链家二手房

本案例用到列表&#xff0c;函数&#xff0c;字符串等知识点&#xff0c;知识点参考链接如下&#xff1a; python基础知识&#xff08;一&#xff09;&输入输出函数 python基础知识&#xff08;二&#xff09;&基本命令 python基础知识&#xff08;三&#xff09;&…

如何在Linux通过docker搭建Plik文件系统并实现无公网IP管理内网文件

文章目录 1. Docker部署Plik2. 本地访问Plik3. Linux安装Cpolar4. 配置Plik公网地址5. 远程访问Plik6. 固定Plik公网地址7. 固定地址访问Plik 本文介绍如何使用Linux docker方式快速安装Plik并且结合Cpolar内网穿透工具实现远程访问&#xff0c;实现随时随地在任意设备上传或者…

盒子模型+响应式布局 + 原型链与继承

盒子模型 是什么 css布局基础,规定了元素在页面上如何呈现,以及元素之间的空间关系 由content paddingbordermargin四部分组成 为什么 盒子模型分为 标准盒子模型: 元素的宽度与高度 只包括content IE盒子模型: 元素的宽度与高度 包括content,padding,border 在实际操作中…

Python实现时间序列ARIMA模型(附带超详细理论知识和完整代码实现)

文章目录 0 结果1 介绍2 建模2.1 预备知识2.1.1 ADF检验结果&#xff08;单位根检验统计量&#xff09;2.1.2 差分序列的白噪声检验&#xff08;这里使用Ljung-Box检验&#xff09;2.1.3 ARIMA模型&#xff08;差分整合移动平均自回归模型&#xff09;的三个参数:p&#xff0c;…

如何在横向渗透攻击中寻到一线生机

横向渗透&#xff0c;作为计算机网络中的一种攻击技术&#xff0c;展现出了攻击者如何巧妙地利用同一级别系统间的漏洞和弱点&#xff0c;扩大其网络访问权限。与纵向渗透不同&#xff0c;横向渗透不关注权限的垂直提升&#xff0c;而是更侧重于在同一层级内扩展影响力。 横向…

【教程】将Vue项目打包为exe项目的教程-我的第一个原生Vue项目

文章目录 前言项目介绍正文&#xff1a;Vue打包exe过程及注意事项1. &#xff08;重要&#xff09;进入我们自己的项目&#xff0c;修改公共路径为相对路径2. &#xff08;重要&#xff09;关于VueRouter的必要修改3. 前端打包4. 拉取electron-quick-start项目5. 修改配置文件6…

【Excel】使用VBA宏简单自定义Excel软件界面

改行做经济师学习Excel&#xff0c;偶有心得&#xff0c;摘录于此&#xff0c;备忘。 言简意赅&#xff0c;仅供自用。 1 实现效果 在Excel的左上角可添加按钮&#xff0c;该按钮的功能可由我们自己通过编写代码定义&#xff0c;能实现特定功能&#xff0c;并且在所有打开的…

Java算法之时间复杂度和空间复杂度的概念和计算

1. 算法效率 如何去衡量一个算法的好坏&#xff1f; 通常我们从时间效率和空间效率两个方面去分析算法的好坏。时间效率即时间复杂度&#xff0c;空间效率被称为空间复杂度。时间复杂度主要是衡量一个算法的运行速度&#xff0c;而空间复杂度主要衡量一个算法所需要的额外空间…

业务与数据的终极对决:如何让大数据成为企业的超能力?

在数字化转型的浪潮中&#xff0c;企业如同在茫茫数据海洋中航行的船只&#xff0c;而数据资产管理就是指引航向的罗盘。但是&#xff0c;当业务需求与数据脱节、数据孤岛林立、业务流程与数据流程不同步、以及业务增长带来的数据管理挑战成为阻碍&#xff0c;我们该如何突破重…

transformer上手(7)—— 快速分词器

1 快速分词器 Hugging Face 共提供了两种分分词器&#xff1a; 慢速分词器&#xff1a;Transformers 库自带&#xff0c;使用 Python 编写&#xff1b;快速分词器&#xff1a;Tokenizers 库提供&#xff0c;使用 Rust 编写。 特别地&#xff0c;快速分词器除了能进行编码和解…

单链表链表专题

1 链表的概念 概念&#xff1a;链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 链表的结构跟⽕⻋⻋厢相似&#xff0c;淡季时⻋次的⻋厢会相应减少&#xff0c;旺季时⻋次的⻋厢会额外增加⼏节。只 需要…