0
点赞
收藏
分享

微信扫一扫

C++算法与数据结构_3

快乐与微笑的淘气 2022-04-13 阅读 63

关系与逻辑表达式

关系表达式

  • 在C++中,关系运算符用于判断表达式之间的大小关系,对两边的值进行6种情况的判断:
    • 大于>和大于等于>=运算符
    • 小于<和小于等于<=运算符
    • 相等==和不相等!=运算符
  • 关系运算符中,表达式结果的类型可以是字符或者数字,但不可以是字符串
  • 关系表达式返回一个布尔值:成立为1(true)代表真,不成立为0(false)代表假

Tips:判断两个数是否相等,用的是==而非=,因为=是用于赋值操作的。

  • 浮点数一般不会用 == 或者 != 来判断,因为可能产生表示误差。
  • 比较两个浮点数是否相等,需要看两个数的差值是否小于一定的精度,比如:
    • 对于浮点数a和b,如果(a - b) < 1e-6 如果值为真,就判断两个浮点数相等。

举例:假设血量是整型数,小六希望判断己方血量hp_a和敌方血量hp_b两个数值之间的关系。

判断己方与敌方血量(整型数)关系的程序段

int hp_a, hp_b;
hp_a = 456;
hp_b = 857;
cout << "己方血量: " << hp_a << " 敌方血量: " << hp_b << endl;

// 关系运算符两边都是变量的基础用法
// 判断 自己血量 是否大于 敌方血量
cout << (hp_a > hp_b) << endl;
// 判断 自己血量 是否大于等于 敌方血量
cout << (hp_a >= hp_b) << endl;
// 判断 自己血量 是否小于 敌方血量
cout << (hp_a < hp_b) << endl;
// 判断 自己血量 是否小于等于 敌方血量
cout << (hp_a <= hp_b) << endl;
// 判断 自己血量 是否等于 敌方血量
cout << (hp_a == hp_b) << endl;
// 判断 自己血量 是否不等于 敌方血量
cout << (hp_a != hp_b) << endl;

// 关系运算符一边是表达式,一边是变量
// 判断 自己回50点血后的血量 是否小于 敌方血量
cout << ((hp_a + 50) < hp_b) << endl;

// 关系运算符一边是变量,一边是数字
// 判断 自己血量 是否小于 100
cout << (hp_a < 100) << endl;

举例:假设血量是浮点数,小六希望判断己方血量 hp_c 和 敌方血量hp_d 是否相等。

判断己方与敌方血量(浮点数)关系的程序段

float hp_c, hp_d;
hp_c = 100.0;
hp_d = 100.0;
cout << ((hp_c - hp_d) < 1e-6) << endl;

逻辑表达式

  • 关系表达式可以判断某个条件是否成立,逻辑表达式中包含了多个关系表达式,可以对多个条件进行判断,例如:
    • 多个条件是否同时成立
    • 多个条件中是否至少有一个成立
    • 某个或某些条件是否不成立
  • C++使用逻辑运算符连接多个关系表达式,从而构建逻辑表达式。
  • 常用的逻辑运算符有以下三种:
    • 逻辑AND运算符&&:判断两个关系表达式是否同时成立
    • 逻辑OR运算符||:判断两个关系表达式是否至少有一个成立
    • 逻辑NOT运算符!:判断某个关系表达式是否不成立C++使用逻辑运算符连接多个关系表达式,从而构建逻辑表达式。
  • 假设p1p2是关系表达式的返回结果,逻辑运算符的运算规则可以参考下表:
p1p2p1&&p2p1llp2!p1
00001
01011
10010
11110

Tips:判断多个条件是否成立时,我们可以组合逻辑运算符,构成更复杂的逻辑表达式。

举例:判断当变量 a 是否是30以下或者100以上的偶数时,可以通过 (a%2==0) && ((a < 30) || (a > 100)) 得到结果。

举例:小六最近在游戏上进步了一点点,他知道有的时候撤不撤退,不只需要看自己血量是否比敌方高,还需要看自己的蓝量是否比敌方高。

假设布尔值 higher_hp 表示自己血量比对方高,higher_mp 表示自己蓝量比对方高。

小六想要知道:“是否自己血量和蓝量都比敌方高”,“是否自己血量和蓝量和中至少有一种比敌方高”,“是否血量没有敌方高”,“是否自己血量和蓝量都没有敌方高”,你能够把这些信息都输出给小六吗?

判断敌我双方血量和蓝量的程序段

// 假设小六血量比敌方高,但是蓝量没有敌方高
bool higher_hp = 1;
bool higher_mp = 0;

// 是否自己血量和蓝量都比敌方高
cout << (higher_hp && higher_mp) << endl;
// 是否自己血量和蓝量和中至少有一种比敌方高
cout << (higher_hp || higher_mp) << endl;
// 是否血量没有敌方高
cout << (!higher_hp) << endl;
// 是否自己血量和蓝量都没有敌方高
cout << (!higher_hp && !higher_mp) << endl;

运算符优先级

  • 至此,我们已经学习的运算符如下:
    • 算术运算符(+ - * / % ++ --等)
    • 赋值运算符(=等)
    • 位运算符(<< >>等)
    • 关系运算符(> >= < <= == !=等)
    • 逻辑运算符(&& || !等)
  • 对于这些常用的运算符,按照计算优先级从高到低(左边更高,右边更低)进行排列,可以得到如下表格:
()! -(负号) ++ --* / %+ -(减号)<< >>== !=&&ll

Tips:对于一个表达式,虽然可以通过计算优先级省略掉括号,但为了代码的可读性,我们在编写时一般都选择把括号加上

习题

举例:生日在2月29日的程序员小键希望用一段代码判断输入的某一年是否为闰年。

  • 判断“闰年”的口诀是:四年一闰,百年不闰,四百年又闰。即闰年分为两种:
    • 一种是被400整除的年份
    • 一种是不被100整除,但是被4整除的年份

为了综合这两个条件,小键通过逻辑表达式来实现了这个功能:

判断闰年的程序段(一)

int year;
cin >> year;
bool is_leap_year;

// 是400的倍数;或者是4的倍数并且不是100的倍数
is_leap_year = (year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0));

cout << is_leap_year << endl;
  • 在C++中,对于逻辑运算符&&||来说:
    • 参与计算的条件返回值为0,就会被当作假
      • 如果year = 2000是400的倍数,year % 400的结果为0,此时(year % 400)会被当作假
    • 参与计算的条件返回值非0,就会被当作真
      • 如果year = 2001不是400的倍数,year % 400结果为1,此时(year % 400)会被当作真

通过这个特性,用逻辑表达式判断闰年也可以这么写:

判断闰年的程序段(二)

int year;
cin >> year;
bool is_leap_year;

is_leap_year = !(year % 400) || (!(year % 4) && (year % 100));

cout << is_leap_year << endl;

if 语句

if 基础用法

  • if 基础用法:控制程序在指定条件下执行指定语句。
  • 语法:
if (成立条件表达式) {
    当条件成立时需要执行的语句
}
  • 语法解析:
    • 成立条件表达式:用圆括号包裹,一般是关系表达式或者逻辑表达式,比如:a<b, a<b && b<c
    • 如果条件成立(成立条件表达式的值为“1或True”),则执行语句;
    • 执行语句可以是一行代码,也可以是多行代码
      • 如果执行语句是多行代码,需要用大括号包裹;
      • 执行语句相比其他语句向右移动一些,就是缩进。读者可以一目了然的知道哪些语句是当条件成立时执行的,可读性更强。

举例:

小键希望用一段代码提醒小戴在下雨时带上伞。

假设天气预报上的降水概率大于40%就表示要下雨,小键需要写一段代码,在输入降水概率后,判断如果要下雨,就输出“请带上伞”。

// 输入一个double类型的变量表示降水概率
double prob_of_precipitation;
cin >> prob_of_precipitation;

// 在降水概率大于40%这个条件成立时,需要执行的语句是:输出“请带上伞”。
if (prob_of_precipitation > 0.4)
    cout << "请带上伞" << endl;

如果降雨条件成立时,要首先输出降水概率,并且输出“请带上伞”,那么小键就需要在执行语句外加上大括号:

double prob_of_precipitation;
cin >> prob_of_precipitation;
if (prob_of_precipitation > 0.4) {
    cout << "降水概率:" << prob_of_precipitation << endl;
    cout << "请带上伞" << endl;
}

if … else 用法

  • if ... else 用法:用来控制程序在指定条件下做事情A,否则做另外去做事情B。
  • 语法:
if (成立条件表达式) {
    当条件成立时需要执行的语句
} else {
    当条件不成立时需要执行的语句
}
  • 举例:

我们都知道未成年人不能进入网吧,网吧老板需要小键帮忙写段代码,根据输入的年龄判断是否可以进入网吧。

如果年龄大于等于18,就输出“允许进入”;否则输出“禁止进入”。

// 先输入一个整型表示年龄
int age;
cin >> age;

// 判断年龄是否大于等于18,成立的话就输出“允许进入”;不成立就输出“禁止进入”。
if (age >= 18)
    cout << "允许进入" << endl; 
else
    cout << "禁止进入" << endl; 

if… else if 用法

  • if ... else if 用法:有些时候,我们会遇到大于两个分支的复杂情况。这时候,我们需要用到 if ... else if 语句,保证在多种情况下,不同条件成立时可以做不同的事情
  • 语法:
if (成立条件表达式1) {
    当条件1成立时需要执行的语句
} else if (成立条件表达式2) {
    条件1不成立但是条件2成立时需要执行的语句
} else {
    当条件1和2都不成立时需要执行的语句
}
  • 语法执行流程:
    • 在条件1成立时进行一些操作;
    • 否则看条件2是否成立;
    • 如果条件2成立,做一些操作;
    • 否则做条件1和2都不成立时需要的操作。
  • 注意点:
    • 成立条件表达式:关系或者逻辑表达式;
    • 最后的一个else:可以没有,你可以选择在条件1和条件2都不成立时,不做任何事情。
  • 举例:

看见小键帮网吧老板的忙,公园售票处也想让小键帮忙写个程序,根据输入的年龄,输出对应的买票政策:如果是老人,就免票;小孩,就半票;否则就全票。

如果我们用年龄对人群做一个划分,假设年龄小于12岁,我们叫小孩;大于等于60岁,我们称之为老人。那么输入年龄,公园售票处该怎么表达对应的操作呢?

// 我们先读入年龄
int age;
cin >> age;

// 先判断是否是老人,是的话直接免票
// 如果不是老人,再判断是否是小孩,是的话半票
// 都不是的话,就全票
if (age >= 60)
    cout << "免票" << endl; 
else if (age < 12)
    cout << "半票" << endl;
else
    cout << "全票" << endl;

if… else if 的延伸用法

  • if ... else if 延伸用法:如果情况需要分成不只三种,我们也可以在else后面再接ifelseifelse,依次判断每个条件是否成立,成立就执行对应的操作,否则就判断下一个条件是否成立:
if (成立条件表达式1) {
    当条件1成立时需要执行的语句
} else if (成立条件表达式2) {
    否则,当条件2成立时需要执行的语句
} else if (成立条件表达式3) {
    否则,当条件3成立时需要执行的语句
} ... else if (成立条件表达式n) {
    否则,当条件n成立时需要执行的语句
} else {
    当上述所有条件都不成立时需要执行的语句
}

if语句嵌套

  • if 语句嵌套:对于条件成立或者不成立的情况下需要执行的语句里,再嵌入if语句表示新的分支。

Tips:很多时候分支的情况会非常的复杂:当某个条件成立或者不成立时,还需要考虑另一个条件是否成立,根据另一个条件的成立与否再进行分支。这时候,就需要用到if语句的嵌套。

  • 用法:
    • 对于最外层的分支,每个分支需要执行的语句都可以再嵌入分支
    • 嵌入的这个分支可以以任何形式出现,可以是if,可以是if ... else,也可以是if ... else if

举例:假设在条件1成立时,我们要通过条件2再进行分支,就可以这样写:

if (成立条件表达式1) {
    if (成立条件表达式2) {
        当条件1和2都成立时需要执行的语句
    }
} else {
    当条件1不成立时需要执行的语句
}
  • 注意点1:如果省略大括号,else默认会匹配到最近的那一个if。
    • 举例:如果不加上大括号的话,下面程序会把最后的else和第二个if匹配起来,表达的就不是我们之前说的意思了。
    if (成立条件表达式1) 
    if (成立条件表达式2) {
        当条件1和2都成立时需要执行的语句
    }
    else {
    当条件1不成立时需要执行的语句
    }
    
  • 注意点2:if语句的嵌套会出现很多的大括号和缩进,大家想想如果有4层以上的嵌套会是什么样的情景?所以为了代码的可读性,尽量避免非必要的多重if语句嵌套。

switch语句

比如聊天机器人需要对不同的情况做出不同的反应,这显然也是一个分支结构。所以我们可以用if语句完成:

// 输入一个字符代表自己的名字
char opt;
cin >> opt;

// 根据不同的名字说出不同的话
if (opt == '6') {
    cout << "主人你好!" << endl;
    cout << "今天你想吃什么" << endl;
}
else if (opt == '1') {
    cout << "小一你好!" << endl;
    cout << "今天天气怎么样?" << endl;
}
else if (opt == '2')
    cout << "你有什么需要帮助的吗?" << endl;
else if (opt == '4' || opt == '5')
    cout << "我不想跟你说话。" << endl;
else
    cout << "我不太清楚你是谁..." << endl;

可以发现所有表示条件成立的表达式都是一样的形式:opt这个变量是否等于某个值。

针对这种情况,有一种专门的语法,叫做switch语句。

switch 用法

  • switch用于表示这样的分支结构:根据某个变量不同的值进行不同的操作。
  • 语法:
switch (变量名) {
    case 变量可能的情况1: 执行语句1; break;
    case 变量可能的情况2: 执行语句2; break;
    ...
    // 可以有任意数量的 case 语句
    default: 执行语句n;
}
  • 语法解析
    • switch 后面的变量名:整型变量(比如int或者char),或者值为整型的表达式
    • 在一个switch中可以有任意数量的case语句。
    • 每个case后跟一个变量可能的值和一个冒号。这个变量可能的值必须与switch中的变量具有相同的数据类型,而且是一个常量,比如1,2,3或者‘A’,‘B’,‘C’或者‘1’,‘2’,‘3’等等。
    • switch后面的变量等于case后的常量时,case后跟的所有语句将被执行,直到遇到break语句为止。
    • break(难点):
      • 当遇到 break 语句时,switch 终止,控制流将跳转到整个 switch 语句后的下一行。
      • case后可以没有break, 如果某个case后没有break语句,程序就会接着往下执行。
        • 举个例子,假设 执行语句1之后没有 break,那么如果变量名 == 变量可能的情况1时,程序会执行执行语句1,然后接着执行 执行语句2,直到碰到break
    • default:一个switch语句可以有一个可选的default情况,出现在switch的结尾。default情况可用于上面所有case都不为真时执行。
  • 举例:

上一步所说的聊天机器人改写成switch语句是这样的:

char opt;
cin >> opt;

switch (opt) {
    // 如果opt=='6',执行完两句cout后,遇见break,就会跳出整个switch
    case '6': 
        cout << "主人你好!" << endl;
        cout << "今天你想吃什么" << endl;
        break;
    case '1': 
        cout << "小一你好!" << endl;
        cout << "今天天气怎么样?" << endl;
        break;
    case '2': 
        cout << "你有什么需要帮助的吗?" << endl; 
        break;
    // 如果opt=='4',由于'4'的 case 后面没有 break
    // 所以会往下执行'5'的 case 后面的语句,直到遇到 break
    case '4': case '5':
        cout << "我不想跟你说话" << endl;
        break;
    default: 
        cout << "我不太清楚你是谁..." << endl;
}
  • Tips:对比这个场景下ifswitch的用法:
    • 如果用if来写会有如下的缺点:
      • 需要很多 opt == '1' 这样的关系表达式
      • 一个分支下如果有多条语句,就需要加上大括号
    • 相比之下,switch就比较简洁。
举报

相关推荐

0 条评论