14 C++ 运算符优先级

14 C++ 运算符优先级

在 C++ 中,运算符的优先级决定了在一个表达式中,哪些运算符先被计算,有助于我们理解复杂表达式的计算顺序。掌握运算符优先级可以帮助我们避免潜在的错误并写出更清晰的代码。

运算符优先级的基本概念

运算符优先级是指运算符在表达式中计算顺序的规则。优先级高的运算符会先于优先级低的运算符被计算。若运算符的优先级相同,则由它们的结合性决定运算的顺序。

结合性

结合性决定了相同优先级的运算符在表达式中如何组合计算。它可以是:

  • 左结合:从左到右计算,例如 -+ 运算符。
  • 右结合:从右到左计算,例如赋值运算符 = 和条件运算符 ?:

常见运算符优先级表

以下是一些常见运算符的优先级,从高到低:

运算符 描述 优先级 结合性
() 函数调用 最高 -
[] 数组下标 -
-> 成员指针访问 -
. 成员访问 -
++ (前置) 前置自增 -
-- (前置) 前置自减 -
! 逻辑非 -
~ 按位取反 -
*, /, % 乘法、除法、取余 左结合
+, - 加法、减法 左结合
<<, >> 位移运算 左结合
<, <=, >, >= 比较运算 左结合
==, != 相等运算 左结合
& 按位与 左结合
^ 按位异或 左结合
` ` 按位或
&& 逻辑与 左结合
` ` 逻辑或
?: 条件运算符 右结合
= 赋值运算 右结合
+=, -= 复合赋值运算 右结合
comma (,) 逗号运算符 最低 左结合

示例代码

让我们通过一些示例来更好地理解运算符优先级。

例1:简单计算

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

int main() {
int a = 10;
int b = 20;
int c = 30;

// 计算表达式
int result = a + b * c; // `*` 的优先级高于 `+`

std::cout << "result: " << result << std::endl; // 输出 610
return 0;
}

在上述代码中,表达式 a + b * c 中,b * c 会先于 a + 被计算,因此最终结果为 10 + 600 = 610

例2:使用括号改变优先级

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

int main() {
int a = 10;
int b = 20;
int c = 30;

// 使用括号改变优先级
int result = (a + b) * c; // 先执行 `a + b`

std::cout << "result: " << result << std::endl; // 输出 900
return 0;
}

在这个例子中,使用括号改变了运算的顺序,使得 a + b 会先计算,最终结果为 (10 + 20) * 30 = 900

总结

理解运算符的优先级和结合性是编写 C++ 程序的基础。熟练掌握这些规则可以帮助你写出更简洁、高效的代码,避免由于优先级误解而导致的错误。使用 () 可以灵活地改变计算顺序,确保逻辑的正确性。

15 STL容器的选择与优化

15 STL容器的选择与优化

在C++的标准模板库(STL)中,选择合适的容器对性能和代码的可读性有极大的影响。不同的容器具有不同的特性和性能表现,因此在应用场景中选择合适的容器是优化程序的重要一步。下面将详细介绍几种常见的 STL 容器的选择和优化策略。

1. 常见的 STL 容器

1.1 vector

  • 特点:动态数组,支持随机访问。
  • 适用场景:元素数量变化不频繁,或者需要频繁访问(push_backpop_back操作性能较高)。
  • 性能:插入和删除操作在尾部是常数时间,其它位置为线性时间。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <vector>

int main() {
std::vector<int> nums;
nums.push_back(1);
nums.push_back(2);
nums.push_back(3);

for (int num : nums) {
std::cout << num << " ";
}
return 0;
}

1.2 list

  • 特点:双向链表,支持快速插入和删除。
  • 适用场景:需要频繁的插入和删除操作,尤其是在中间的位置。
  • 性能:插入和删除操作为常数时间,但不支持随机访问。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <list>

int main() {
std::list<int> numList;
numList.push_back(1);
numList.push_back(2);
numList.push_back(3);

numList.erase(numList.begin()); // 删除第一个元素

for (int num : numList) {
std::cout << num << " "; // 输出:2 3
}
return 0;
}

1.3 deque

  • 特点:双端队列,支持在两端进行插入和删除。
  • 适用场景:需要在两端操作的场景,具有随机访问能力。
  • 性能:头部和尾部插入/删除常数时间,中间插入/删除线性时间。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <deque>

int main() {
std::deque<int> numDeque;
numDeque.push_front(1);
numDeque.push_back(2);

for (int num : numDeque) {
std::cout << num << " "; // 输出:1 2
}
return 0;
}

1.4 setmap

  • 特点:基于红黑树实现,支持自动排序。
  • 适用场景:需要唯一值(set)或键值对(map)且需频繁查找的情况。
  • 性能:插入、删除、查找操作时间复杂度为 O(log n)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <set>

int main() {
std::set<int> numSet;
numSet.insert(3);
numSet.insert(1);
numSet.insert(2);

for (int num : numSet) {
std::cout << num << " "; // 输出:1 2 3
}
return 0;
}

2. 容器性能优化

2.1 选择合适的容器类型

在选择容器时,不要仅仅考虑功能,还要关注性能。对于频繁的插入和删除操作,应优先选择 listdeque;而对于需要快速随机访问的场景,vector 是更好的选择。

2.2 预分配内存

对于 vector,如果知道要存储的元素个数,可以使用 reserve() 方法预先分配内存,从而避免多次内存重分配带来的性能损失。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <vector>

int main() {
std::vector<int> nums;
nums.reserve(100); // 预分配100个元素的空间

for (int i = 0; i < 100; ++i) {
nums.push_back(i);
}

std::cout << "Vector size: " << nums.size() << std::endl;
return 0;
}

2.3 使用合适的迭代器

在操作容器的元素时,可以使用迭代器而不是索引,这在某些情况下可以提升代码的性能和可读性。当需要在多个容器间操作时,迭代器也提供了更好的通用性。

3. 结论

选择和优化 STL 容器需要考虑性能需求、操作频率、内存管理等因素。了解每种容器的特性及其适用场景,可以帮助我们在实际开发中做出更明智的决策,从而提高程序性能和可读性。通过实践和深入理解容器的特性,我们能够在 C++ 编程中充分发挥 STL 的强大能力。

15 C++ 条件语句教程

15 C++ 条件语句教程

在 C++ 中,条件语句用于根据特定条件的真假来控制程序的执行流。常见的条件语句有 ifelseswitch。本小节将会详细介绍这些语句的使用。

1. if 语句

if 语句用于判断一个条件。如果条件为真(true),则执行特定的代码块。

基本语法

1
2
3
if (条件) {
// 当条件为真时执行的代码
}

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;

int main() {
int number;

cout << "请输入一个整数: ";
cin >> number;

if (number > 0) {
cout << "这个数是正数。" << endl;
}

return 0;
}

if-else 语句

if-else 语句用于在条件为假(false)时执行其他代码。

基本语法

1
2
3
4
5
if (条件) {
// 当条件为真时执行的代码
} else {
// 当条件为假时执行的代码
}

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;

int main() {
int number;

cout << "请输入一个整数: ";
cin >> number;

if (number > 0) {
cout << "这个数是正数。" << endl;
} else {
cout << "这个数不是正数。" << endl;
}

return 0;
}

if-else if-else 语句

当有多个条件需要判断时,可以使用 if-else if-else 结构。

基本语法

1
2
3
4
5
6
7
if (条件1) {
// 当条件1为真时执行的代码
} else if (条件2) {
// 当条件2为真时执行的代码
} else {
// 当所有条件都不满足时执行的代码
}

示例代码

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

int main() {
int number;

cout << "请输入一个整数: ";
cin >> number;

if (number > 0) {
cout << "这个数是正数。" << endl;
} else if (number < 0) {
cout << "这个数是负数。" << endl;
} else {
cout << "这个数是零。" << endl;
}

return 0;
}

2. switch 语句

switch 语句用于根据一个变量的值来选择执行不同的代码块。适用于多个选择的情况。

基本语法

1
2
3
4
5
6
7
8
9
10
switch (表达式) {
case1:
// 执行代码块1
break;
case2:
// 执行代码块2
break;
default:
// 执行默认代码块
}

注意事项

  • 每个 case 后面通常需要有一个 break 语句来结束当前的代码块,如果没有,程序将继续执行后面的 case 代码。
  • default 是可选的,用于处理所有没有匹配的情况。

示例代码

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
#include <iostream>
using namespace std;

int main() {
int day;

cout << "请输入一个数字(1-7)以代表星期几: ";
cin >> day;

switch (day) {
case 1:
cout << "星期一" << endl;
break;
case 2:
cout << "星期二" << endl;
break;
case 3:
cout << "星期三" << endl;
break;
case 4:
cout << "星期四" << endl;
break;
case 5:
cout << "星期五" << endl;
break;
case 6:
cout << "星期六" << endl;
break;
case 7:
cout << "星期日" << endl;
break;
default:
cout << "无效输入" << endl;
break;
}

return 0;
}

总结

  • 使用 if 来对条件进行判断,满足条件则执行相应的代码。
  • 使用 if-elseif-else if-else 处理多个条件。
  • 使用 switch 简化多个 if 条件的逻辑判断,使代码更加清晰。

通过上述内容,您应该对 C++ 中的条件语句有了基本的理解。希望能够帮助您在编程中做出正确的逻辑判断!