1、概念
在C++中,枚举(Enumeration)是一种数据类型,它允许程序员定义一个变量并指定它可以取的那些固定值的集合。枚举的主要目的是提高代码的可读性和维护性,通过使用有意义的名称而不是数字来表示状态、类型或其他固定集合的值。
2、枚举的基本语法
enum EnumName {
Value1,
Value2,
Value3,
// 更多的值
};
- enum 关键字用于定义枚举。
- EnumName 是枚举的名称。
- Value1, Value2, Value3, ... 是枚举中的元素,也称为枚举值或枚举常量。
示例:
enum Color {
RED,
GREEN,
BLUE
};
Color myColor = RED;
在这个例子中,Color是一个枚举类型,包含三个可能的值:RED、GREEN和BLUE。然后声明了一个Color类型的变量myColor,并将其初始化为RED。
枚举的特点
- 枚举提供了一种将数字与名字关联起来的方法,使得代码更加清晰易懂。
- 枚举类型的变量只能接受枚举中定义的值,这有助于减少错误和提高代码的安全性。
- 在C++11及以后的版本中,可以为枚举类型指定底层类型,例如
enum Color: unsigned int { RED, GREEN, BLUE };
这里Color的底层类型被指定为unsigned int。
- C++11引入了“枚举类”(enum class或enum struct),提供了更强的类型安全和作用域控制。
枚举是C++中用于表示一组有限的、命名的值的强大工具,通过使用枚举,可以使得代码更加简洁、安全和易于维护。
1.枚举的基本使用方法
以下是枚举的一些基本使用方式:
1.定义枚举类型(定义一个枚举类型通常是为了表示一个变量可能的几种固定值。)
enum Color {
RED,
GREEN,
BLUE
};
在这个例子中,Color 是一个枚举类型,它有三个可能的值:RED、GREEN和BLUE。
2.使用枚举类型的变量(一旦定义了枚举类型,就可以使用这个类型来声明变量,并给这个变量赋予枚举中的任意一个值。)
Color myColor;
myColor = RED;
这里,myColor被声明为Color类型,并被赋值为RED。
3.枚举类型在switch语句中的应用(枚举类型经常与 switch 语句一起使用,以便根据枚举变量的值执行不同的操作。)
switch (myColor) {
case RED:
// 处理红色的情况
break;
case GREEN:
// 处理绿色的情况
break;
case BLUE:
// 处理蓝色的情况
break;
}
4.指定枚举值(默认情况下,枚举的第一个值为0,后续的值依次递增。但是,也可以手动为枚举的每个成员指定一个值。)
enum StatusCode {
OK = 200,
NotFound = 404,
Error = 500
};
在这个例子中,StatusCode枚举的每个成员都被赋予了一个特定的整数值。
5. 枚举类(C++11及以后)
C++11引入了枚举类(也称为强类型枚举),提供了更好的类型安全和作用域控制。
enum class Direction {
Up,
Down,
Left,
Right
};
Direction dir = Direction::Up;
在这个例子中,Direction是一个枚举类,它的成员可以通过Direction::的方式访问这有助于避免命名冲突,并提高代码的清晰度。
6. 枚举的底层类型指定(C++11及以后)
在C++11中,还可以指定枚举的底层类型,以控制枚举变量的大小和类型。
enum class ErrorCode : unsigned int {
None = 0,
Low = 1,
High = 2
};
在这个例子中,ErrorCode的底层类型被指定为unsigned int。
-
习题
Maggie是以机器人控闻名的高中生。某一天,Maggie终于入手了最新款的机器人。作为最新的机器人,当然有了与以往不同的功能了,那就是它能够自动行走。Maggie的新模型可以按照输入的命令进行移动,命令包含 E、S、W、N 四种,分别对应四个不同的方向,依次为东、南、西、北。执行某个命令时,它会向着对应方向移动一个单位。作为新型机器人,自然不会只单单执行一个命令,它可以执行命令串。对于输入的命令串,每一秒它会按照命令行动一次。而执行完命令串最后一个命令后,会自动从头开始循环。在 0 时刻时Maggie将机器人放置在了 (0,0) 的位置,并且输入了命令串。她想要知道 T 秒后机器人所在的位置坐标。
假设当前机器人的位置是 (x,y)。那么对于四种方向的移动,它坐标的改变分别为:
向东移动,坐标改变改变为 (x+1,y);向南移动,坐标改变改变为 (x,y−1);
向西移动,坐标改变改变为 (x−1,y);向北移动,坐标改变改变为 (x,y+1)。
源码:
#include <iostream>
#include <string>
using namespace std;
int main() {
string commands;
int T;
// 读取命令串和时间T
cin >> commands >> T;
int x = 0, y = 0; // 初始位置
int dx = 0, dy = 0; // 完整命令串执行一次后的位移
int length = commands.length(); // 命令串的长度
// 计算一个完整命令串执行一次后的位移
for(char command : commands) {
switch(command) {
case 'E': dx++; break;
case 'S': dy--; break;
case 'W': dx--; break;
case 'N': dy++; break;
}
}
// 计算执行完整命令串的次数和剩余部分
int fullCycles = T / length;
int remainder = T % length;
// 根据完整次数更新位置
x += dx * fullCycles;
y += dy * fullCycles;
// 处理剩余部分
for(int i = 0; i < remainder; i++) {
switch(commands[i]) {
case 'E': x++; break;
case 'S': y--; break;
case 'W': x--; break;
case 'N': y++; break;
}
}
// 输出T秒后的位置坐标
cout << "(" << x << "," << y << ")" << endl;
return 0;
}
示例:
假设commands为"ENWS",T为5。命令串长度为4,所以fullCycles为1(5/4),remainder为1(5%4)。
- 单次命令串执行后,dx=0(东移一次,西移一次,抵消),dy=0(北移一次,南移一次,抵消)。
- 执行完整命令串1次后,位置仍然是(0,0)。
- 处理剩余部分,即"ENWS"中的第一个命令'E',物体向东移动1单位。
最终位置为(1,0)。
枚举的思想:
代码中,虽然直接使用了数学计算而非枚举所有可能性,但我们可以将对命令串一次完整执行后位移的计算理解为一种“枚举”的思想。这里的“枚举”不是传统意义上遍历所有可能的选项,而是指通过一次性考虑命令串中每个命令对位移的贡献,来“枚举”出执行一次命令串后机器人的总位移。这种处理方式相比于逐个执行命令并更新位置,更接近于一种批量处理或总结性计算的方法。
注:该方法需要在先配置c++11之后的dev中才适用
具体来说,以下部分体现了这种“枚举”的思想:
// 计算一个完整命令串执行一次后的位移
for(char command : commands) {
switch(command) {
case 'E': dx++; break;
case 'S': dy--; break;
case 'W': dx--; break;
case 'N': dy++; break;
}
}
在这段代码中,我们遍历命令串中的每个命令,根据命令的类型(E、S、W、N),计算出执行这一系列命令后机器人的总位移(dx, dy)。这相当于“枚举”了命令串中每个命令对位移的影响,并将它们累加起来得到了总位移
然后,通过将这个总位移乘以完整命令串被执行的次数,并处理剩余的命令,我们能够高效地计算出T秒后机器人的位置,而无需逐秒模拟机器人的移动。这种方法在处理大量数据时尤其有效,因为它避免了大量的重复计算。
这段代码是一个简单的C++程序,用于根据一系列命令和时间T计算最终位置。下面是对每一部分的详细解释:
#include <iostream>
#include <string>
这两行代码包含了C++标准库中的两个头文件:iostream和string。iostream提供了输入输出功能,而string提供了字符串操作的功能。
using namespace std;
这行代码使得在std命名空间中定义的所有名称(如cin、cout和string)都可以不加std::前缀直接使用。
int main() {}
这是程序的主函数,C++程序的执行从这里开始。
string commands;
int T;
// 读取命令串和时间T
cin >> commands >> T;
这几行代码定义了两个变量:一个字符串commands和一个整数T。然后,它们从标准输入(通常是键盘)读取一系列命令和时间T。
int x = 0, y = 0; // 初始位置
int dx = 0, dy = 0; // 完整命令串执行一次后的位移
int length = commands.length(); // 命令串的长度
这里定义了四个整数变量:x和y表示初始位置,初始化为0;dx和dy表示执行一次完整命令串后的位移,也初始化为0;length用于存储命令串的长度。
for(char command : commands) {
switch(command) {
case 'E': dx++; break;
case 'S': dy--; break;
case 'W': dx--; break;
case 'N': dy++; break;
}
}
这个循环遍历命令串中的每个字符(命令),根据命令(东E、南S、西W、北N)更新dx和dy的值,以计算执行一次完整命令串后的位移。
计算单次命令串的位移
这个步骤涉及遍历整个命令串一次,并根据每个命令('E', 'S', 'W', 'N')更新位移量。这里的位移是指,如果你从一个初始点开始,完整地按照命令串执行一遍移动后,你会移动到哪里。例如,如果命令串是 "ENW",执行一次后的位移将是向东移动1单位,向北移动1单位,然后向西移动1单位,最终位移是向北移动1单位。
- 'E'(东)命令使dx(东西方向的位移)增加1。
- 'S'(南)命令使dy(南北方向的位移)减少1。
- 'W'(西)命令使dx减少1。
- 'N'(北)命令使dy增加1。
完成遍历后,dx和dy共同表示了执行一次完整命令串后的总位移。
int fullCycles = T / length;
int remainder = T % length;
这两行代码计算完整命令串可以在时间T内执行的次数(fullCycles)和剩余部分(remainder),使用了整数除法和取模运算。
x += dx * fullCycles;
y += dy * fullCycles;
根据完整命令串执行的次数更新位置x和y。
for(int i = 0; i < remainder; i++) {
switch(commands[i]) {
case 'E': x++; break;
case 'S': y--; break;
case 'W': x--; break;
case 'N': y++; break;
}
}
这个循环处理剩余部分的命令,根据每个命令更新x和y的值。
计算完整命令串的执行次数和剩余部分
给定总时间T和命令串的长度,这个步骤计算在时间T内可以完整执行命令串的次数(fullCycles),以及在最后一个周期中可能未完全执行的命令数(remainder)。
- 完整执行次数(fullCycles):这是时间T内可以完整执行命令串的次数。计算方法是用T除以命令串的长度。例如,如果T是10,命令串长度是3,那么完整执行次数是3次,因为10除以3得到3余1。
- 剩余部分(remainder):这是在最后一个周期内未完全执行的命令数。计算方法是用T对命令串的长度取余。在上面的例子中,剩余部分是1,因为10除以3余1。
这两个计算结果使程序能够精确地模拟在给定时间内命令串的执行情况,包括完整次数的执行对位置的影响,以及最后不完整执行的命令对位置的最终影响。
cout << "(" << x << "," << y << ")" << endl;
最后,这行代码输出时间T后的位置坐标。
return 0;
这行代码表示程序正常结束。main函数返回0通常表示程序成功执行。