slacr_

Just to record my life and thoughts.
笔记/编程/杂乱/极简

[C++Task]

Apr 16, 2023C_C++3659 words in 24 min

C++作业

task2_3

题目

教材习题4_20:定义满足要求的复数类Complex类
【问题描述】
定义一个复数类Complex,使得下面的代码能够工作。(注:下列代码需放在主函数中。)
Complex c1(3,5); //用复数3+5i初始化c1
Complex c2=4.5; //用实数4.5初始化c2
c1.add(c2); //将c1与c2相加,结果保存在c1中
c1.show(); //将c1输出(这时的结果应该是7.5+5i)
【输入形式】

【输出形式】
7.5+5i
【样例输入】
【样例输出】
7.5+5i

解答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <string>
using namespace std;
class Complex {
public:
double a;
double b;
Complex() :a(0), b(0) {};
Complex(int a, int b):a(a), b(b){}
Complex(double num) { // 重载拷贝构造
this->a = num;
this->b = 0;
}
Complex& add(Complex& comp) {
a += comp.a;
b += comp.b;
return *this;
}
Complex& operator=(double num) {
this->a = num;
return *this;
}
void show() {
cout << this->a << showpos << this->b<< "i" << endl;
}
};
int main() {
Complex c1(3, 5); //用复数3+5i初始化c1
Complex c2 = 4.5; //用实数4.5初始化c2 // 这个相当于c2(4.5), 要重载的是拷贝构造,而不是内置的=运算符
c1.add(c2); //将c1与c2相加,结果保存在c1中
c1.show(); //将c1输出(这时的结果应该是7.5+5i)
return 0;
}

ClassType c = value 相当于 ClassType c(value)

task3_1

题目

编写数学类,能求开平方,sin 绝对值,圆面积等操作
【样例输入输出】
input a number:3.5
the result of sqrt is:1.87083
the result of sin is:-0.350783
the result of fabs is:3
the result of fabs is:3.5
the result of area is:38.4845

解答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <string.h>
using namespace std;
#include <cmath>
class myMath {
public:
static double mysqrt(double x);
static double mysin(double x);
static double myfabs(double x);
static int myfabs(int x);
static double circleArea(double x);
private:
const static double PI;
};
const double myMath::PI = 3.1415926;
double myMath::mysin(double x) {
return sin(x);
}
double myMath::mysqrt(double x) {
return sqrt(x);
}
double myMath::myfabs(double x)
{
return fabs(x);
}
int myMath::myfabs(int x)
{
return fabs(x);
}
double myMath::circleArea(double x)
{
return PI * x * x;
}
int main()
{
double x;
cout << "input a number:";
cin >> x;
cout << "the result of sqrt is:" << myMath::mysqrt(x) << endl;
cout << "the result of sin is:" << myMath::mysin(x) << endl;
cout << "the result of fabs is:" << myMath::myfabs((int)x) << endl;
cout << "the result of fabs is:" << myMath::myfabs(x) << endl;
cout << "the result of area is:" << myMath::circleArea(x) << endl;
return 0;
}

编写工具类, 使用静态方法. 构造函数最好给成private,不能实例化对象. 只能通过类名调用

task5_1

解答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include  <iostream>
#include <string>
using namespace std;
class Mammal
{
public:
Mammal(string name) :name(name)
{
cout << "Con.Mammal" << endl;
}
~Mammal()
{
cout << "Des.Mammal" << endl;
}
protected:
string name;
};
//
class Dog : public Mammal {
public:
Dog(string name) :Mammal(name) { // 这一步
cout << "Con.Dog:" << Mammal::name << endl;
}
~Dog() {
cout << "Des.Dog:" << name << endl;
}

};
int main()
{
string name;
cout << "Input Dog Name:";
cin >> name;
Dog d(name);
return 0;
}

派生类构造函数给继承的基类初始化

task6_3

题目

【问题描述】
从键盘中读入最多不超过50个学生的学生信息(包括空格隔开的姓名、学号、年龄信息,以学号从低到高排序)

人员类:包含姓名,年龄。

学生类:继承自人员类,增加学号。

【输入形式】
每次键盘读入最多不超过50个学生的学生信息:
第一行为学生人数;
后面每一行为空格隔开的学生学号、姓名、年龄,其中学号和年龄都是整数。
【输出形式】
分别以姓名顺序(从低到高)和年龄顺序(从低到高)将学生信息输出,每行输出一位学生的信息,其中学号占3位,姓名(英文)占6位,年龄占3位,均为右对齐。年龄相同时按姓名从低到高排序。两种顺序的输出结果用一行空行相隔。
【输入样例】

4
1 aaa 22
45 bbb 23
54 ddd 20
110 ccc 19
【输出样例】

1 aaa 22
45 bbb 23
110 ccc 19
54 ddd 20
110 ccc 19
54 ddd 20
1 aaa 22
45 bbb 23

解答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#include <algorithm>
#include <iomanip>

class Person {
public:
string name;
int age;
Person(){}
Person(string name, int age) : name(name), age(age){}
};

class Student : public Person {
public:
int code;
Student(){}
Student(int code, string name, int age): code(code), Person(name, age){}

};

class myPred {
public:
bool operator()(Student s1, Student s2) {
return s1.name < s2.name;
}
};

class myPred2 {
public:
bool operator()(Student s1, Student s2) {
return s1.age < s2.age;
}
};

void printvStus(vector<Student>& vStus) {
// 打印Stu数组
for (vector<Student>::iterator it = vStus.begin(); it != vStus.end(); it++) {
cout << setw(3) << it->code << setw(6) << it->name << setw(3) << it->age << endl;
}
}

int main() {
vector<Student> vStus;
int num;
cin >> num;
int code;
string name;
int age;
// 初始化vStus
for (int i = 0; i < num; i++) {
cin >> code >> name >> age;
vStus.push_back(*(new Student(code, name, age)));
}
// 排序, 按姓名
sort(vStus.begin(), vStus.end(), myPred());
printvStus(vStus);
cout << endl;
sort(vStus.begin(), vStus.end(), myPred2());
// 排序, 按学号
printvStus(vStus);
return 0;
}

很基础的继承然后排序
要引入 iomanip
setw()设置输出流占位, 后面还可以跟setfill()指定填充符号

task7_3

题目

【问题描述】
下面的程序能得到预期的结果吗?如何避免类似问题的发生?
请修改程序,使它得到我们想要的结果。即希望两个输出的值相同。
提示:struct在C++中也可以用来定义类,它与class的不同在于struct定义的类成员的默认访问权限是public。
#include
using namespace std;
struct Base1 {int x;};
struct Base2 {float y;};
struct Derived : Base1,Base2{};
int main()
{
Derived *pd=new Derived;
pd->x=1;pd->y=2.0f;
void *pv = pd;
Base2 pb=static_cast<Base2>(pv);
cout<y<<" "<y<<endl;
delete pd;
return 0;
}
【输入形式】

【输出形式】
2 2

解答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
struct Base1 { int x; };
struct Base2 { float y; };
struct Derived : virtual Base1, virtual Base2 {};
int main()
{
Derived* pd = new Derived;
pd->x = 1;
pd->y = 2.0f;
// void* pv = pd;
// Derived*转void*再转Base2* 会丢失数据, 因为Derived中继承的是vbptr指针,
// 转void*丢失指针信息, 再转Base* 会按照 float 类型 解释对应的 vbptr,
// 正确的做法应该直接将Derived*转Base2*, 编译器会改变偏置值, 使指针名(对象入口)偏置到对应位置.
// 正确写法:
Base2* pb = static_cast<Base2*>(pd);
// Base2* pb = static_cast<Base2*>(pv);
cout << pd->y << " " << pb->y << endl;
delete pd;
return 0;
}

task9_1

题目

对类Point重载“++”(自增)、“–”(自减)运算符,要求同时重载前缀和后缀。

解答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include  <iostream>
using namespace std;

class Point {
public:
int x, y;
Point() {};
Point(int x, int y) : x (x), y(y) {}
// 前置++
Point& operator++() {
this->x++;
this->y++;
return *this;
}
// 后置++
Point& operator++(int) {
Point temp = *this;
this->x++;
this->y++;
return temp;
}
Point& operator--() {
this->x--;
this->y--;
return *this;
}
Point& operator--(int) {
Point temp = *this;
this->x--;
this->y--;
return temp;
}
void display() {
cout << "(" << x << "," << y << ")" << endl;
}
};

int main()
{
Point a, b(5, 5);
a = b++;
a.display();
a = ++b;
a.display();
a = --b;
a.display();
a = b--;
a.display();
}

task9_2

题目

定义一个时间类CTime,分钟和秒钟是其两个私有成员数据。输入一个起始时间和一个结束时间(起始时间早于结束时间),通过运算符重载-(减号),计算这两个时间相隔多少秒钟。说明:这两个时间在同一小时之内,且采用60分钟60秒钟的计时分式,即从00:00-59:59。

解答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include  <iostream>
using namespace std;
#define N 100

class CTime {
public:
int minute;
int hour;
CTime() : minute(0), hour(0) {};
void input() {
cin >> hour >> minute;
}
bool beZero() {
return (minute == 0 && hour == 0);
}
int getTotalMinutes() {
return minute + hour * 60;
}

CTime& operator-(CTime& ct) {
int left = getTotalMinutes() - ct.getTotalMinutes();
hour = left / 60;
minute = left % 60;
return *this;
}

};

ostream& operator<<(ostream& o, CTime& ct) {
o << ct.getTotalMinutes() << endl;
return o;
}

int main()
{
CTime time[N];
int count = -1;
do {
count++;
time[2 * count].input();
time[2 * count + 1].input();
} while (!(time[2 * count].beZero() && time[2 * count + 1].beZero()));
for (int i = 0; i < count; i++) {
cout << time[2 * i + 1] - time[2 * i] << endl;
}
return 0;
}

task10_1

题目

约瑟夫问题:n个骑士编号1,2,…,n,围坐在圆桌旁。编号为1的骑士从1开始报数,报到m的骑士出列,然后下一个位置再从1开始报数,找出最后留在圆桌旁的骑士编号。

解答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<iostream>
#include<vector>
using namespace std;


int main() {
vector<int> a;
int n, m, x = 0;
cout << "Input n and m:";
cin >> n >> m;
a.resize(n);
for (int i = 0; i < n; i++) {
a[i] = i + 1;
}
//
vector<int>::iterator vit = a.begin();
while (a.size() > 1) {
for (int i = 0; i < m - 1; i++) { // 取模
vit++;
if (vit == a.end()) vit = a.begin();
}
int dis = distance(begin(a), vit);
a.erase(vit); // 擦除点之后的迭代器失效, 得重新获取
vit = (a.begin() + dis == a.end() ? a.begin() : a.begin() + dis); // 如果清除最后一个需要置为begin
}

//
cout << "Result:" << a[0] << endl;
return 0;
}

调试了半天, 主要实现迭代器怎么取模, 返回迭代器之间的距离用std::distance().

第一眼想到方法的是不改变vector大小:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include<iostream>
#include<vector>
using namespace std;

int getSurvivorNum(vector<int>& v) {
int num = 0;
for (auto it : v) {
if (it != 0) {
num++;
}
}
return num;
}



int soluteJoselphRing(vector<int>& v, int m) {
int i = 0;
while (getSurvivorNum(v) > 1) {
int dist = 0;
int total = 1;
while (true) {
dist++;
if (v[(i + dist) % v.size()] != 0) {
total++;
}
if (total == m) break;
}
i = (i + dist) % v.size();
v[i++] = 0;
}
for (auto it : v) {
if (it != 0) {
v[0] = it;
return it;
}
}
}

int main()
{
vector<int> a;
int n, m, x = 0;
cout << "Input n and m:";
cin >> n >> m;
a.resize(n);
for (int i = 0; i < n; i++)
{
a[i] = i + 1;
}
//
soluteJoselphRing(a, m);
//
cout << "Result:" << a[0] << endl;
return 0;
}

6-47

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// 表驱动法
class MyDate {
public:
MyDate(int m = 1, int d = 1, int y = 1900) :month(m), day(d), year(y) {}
void setDate(int m, int d, int y) {
if (d > 31 || m > 12 || m < 1) {
month = 1;
day = 1;
year = 1900;
return;
}
month = m;
day = d;
year = y;
}
friend ostream& operator<<(ostream& os, const MyDate& date) {
static string month_name[13] = { "", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
os << month_name[date.month] << " " << date.day << ", " << date.year;
return os;
}
MyDate& operator++() {
int month_days = days(month, year);
if (day < month_days) {
day++;
} else {
day = 1;
if (month < 12) {
month++;
} else {
month = 1;
year++;
}
}
return *this;
}
MyDate operator++(int) {
MyDate temp(*this);
++(*this);
return temp;
}
MyDate& operator+=(int days) {
for (int i = 0; i < days; i++) {
++(*this);
}
return *this;
}
private:
int month, day, year;
int days(int m, int y) {
static int month_days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (m == 2 && ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0))) {
return 29;
}
return month_days[m];
}
};

task12

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<iostream>
#include<string>
#include<iomanip>
#define MaxWid 20
using namespace std;


int main() {
int n;
cin >> n;
int snakeMap[MaxWid][MaxWid] = { 0 };
int num = 1;
for (int i = 0; i < (n + 1) / 2; i++) {
// 总共 n x n 方阵, 从外向内有 (n+1)/2 层
// 第一个从左到右的情况必须是满一行的, 因为奇数情况下需要最后填一次
// 其他的随便循环怎么写, 把一圈遍历完就可以
for (int j = i; j < n - i; j++) {
snakeMap[i][j] = num++; // 从左向右
}
for (int j = i + 1; j < n - 1 - i; j++) {
snakeMap[j][n - 1 - i] = num++; // 从上往下
}
for (int j = i; j < n - 1 - i; j++) {
snakeMap[n - 1 - i][n - 1 - j] = num++; // 从右往左
}
for (int j = i; j < n - 1 - i; j++) {
snakeMap[n - 1 - j][i] = num++; // 从下往上
}
}

//int i, j, k;
//for (k = 0; k <= 2/n; k++) {
// for (j = k; j < n - k; j++) snakeMap[k][j] = num++;
// for (i = k + 1; i < n - k; i++) snakeMap[i][n - k - 1] = num++;
// for (j = n - k - 1 - 1; j >= k; j--) snakeMap[n - k - 1][j] = num++;
// for (i = n - k - 1 - 1; i > k; i--) snakeMap[i][k] = num++;
//}
// 课上给的答案, 原理都一样, 外层条件最好还是按 k < (n + 1) / 2, 或 n/2取上限更准确, 不然偶数情况多了几次无效判断
//打印输出
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout << setw(4) << setfill('*') << snakeMap[i][j];
}
cout << endl;
}
return 0;
}

写的另一种解法, 很巧妙

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<iostream>
#include<string>
#include<iomanip>
#include<vector>
using namespace std;


struct direction {
pair<int, int> left = make_pair(0, 1);
pair<int, int> right = make_pair(0, -1);
pair<int, int> up = make_pair(-1, 0);
pair<int, int> down = make_pair(1, 0);
};

direction d;
pair<int, int> directions[] = { d.left, d.down, d.right, d.up };


int main() {
int n;
cin >> n;
vector<vector<int>> arr;
arr.resize(n);
for (int i = 0; i < arr.size(); i++) { arr[i].resize(n);}
int idx = 0;
int i = 0, j = 0;
int num = 1;
pair<int, int> next = directions[0];
int size = n;
while (num <= n*n) { // 这里可以填[n*n, 2*n*n -1], 超过了会旋转回去
arr[i][j] = num++;
// 四个点转向
if ((i == n - size && j == size - 1) || (i == size - 1 && j == size - 1) || (i == size - 1) && (j == n - size) || (i == n - size + 1 && j == n - size)) {
next = directions[++idx % 4];
if (i == n - size + 1 && j == n - size) size--; // 缩小规模
}
i += next.first;
j += next.second;
}

for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout << setw(4) << setfill('*') << arr[i][j];
}
cout << endl;
}
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<iostream>
#include<string>
#include<iomanip>
#include<bitset>
using namespace std;

int main() {
cout << "Input n:" << endl;
int n;
cin >> n;
cout << "Dec:" << setiosflags(ios_base::dec) << n << " " << resetiosflags(ios_base::dec);
cout << "Oct:" << setiosflags(ios_base::oct) << n << " " << resetiosflags(ios_base::oct);
cout << "Hex:" << setiosflags(ios_base::hex) << n << " " << resetiosflags(ios_base::hex);

//cout << endl;
//cout << oct << n << endl;
//cout.setf(ios_base::uppercase);
//cout << hex << n << endl;
//cout << bitset<8>{255} << endl; // 1111 1111
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<iostream>
#include<string>
#include <sstream>
using namespace std;

template<class T>
inline string toString(const T &v) {
ostringstream os; // 创建输出字符串流
os << v; // 写入数据
return os.str(); // 返回输出字符串流生成的字符串
}

template<class T>
inline T fromString(const string& str) {
istringstream is(str); // 创建输入字符串流
T v;
is >> v; // 从输入字符串流中读取 T 类型的数据
return v;
}

int main() {
cout << toString(123).append(toString('&')) << endl;

cout << fromString<int>("34&56") << endl; // 只读取第一个该类型的数据
cout << fromString<double>("56.78**") << endl;
return 0;
}
  • Author:

    slacr_

  • Copyright:

  • Published:

    April 16, 2023

  • Updated:

    April 16, 2023

Buy me a cup of coffee ☕.

1000000