跳到主要内容C 语言基础转向 C++ 的实战指南 | 极客日志C++算法
C 语言基础转向 C++ 的实战指南
从 C 语言过渡到 C++ 时,核心在于掌握标准库与面向对象思维。本文梳理了 cin/cout 输入输出、string 子串处理、sort 排序与去重、二分查找等基础操作,并详解 queue、stack、map、set 等 STL 容器的用法。此外包含 fast io、lambda 表达式及优先队列等进阶技巧,帮助开发者快速提升编码效率与算法实现能力。
为什么要转 C++
C 语言入门简单,但深入后维护成本高且缺乏便利工具。比如排序,C 需要手写比较函数配合 qsort,而 C++ 的 std::sort 直接可用。更重要的是,C++11 之前语法与 C 高度兼容,对于算法竞赛而言,C++ 基本等于 C 加上强大的 STL 库,迁移成本极低。
C++ 语言基础
新手入门只需记住这个骨架:
#include <bits/stdc++.h>
using namespace std;
int main(void) {
return 0;
}
这里多了 using namespace std; 和 #include <bits/stdc++.h>。前者用于简化命名空间调用,后者是竞赛常用的万能头文件(本地 GCC 环境可能需要配置)。如果只为了打比赛,后续无需记忆具体头文件。
C++ 如何输入输出
#include <iostream>
#include <string>
using namespace std;
int main(void) {
int n;
string s;
cin >> n;
cin >> s;
cout << n << "\n" << s << endl;
}
<iostream> 对应 C 语言的 <stdio.h>,<string> 则是 C++ 特有的字符串类。相比 C 语言需要记忆 %d、%s 等格式化符号,C++ 直接使用 cin 和 cout,类型安全且直观。
C++ string 相关
C 语言处理字符串往往需要手动管理内存,容易出错。C++ 的 string 类封装了这些细节,常用方法如下。
去除前导空格
#include <iostream>
#include <string>
using std;
{
string s;
((cin, s)) {
pos = s.();
s.(, pos);
cout << s << ;
}
cout << ;
}
namespace
int main(void)
while
getline
int
find_first_not_of
" "
erase
0
"\n"
"hello , world"
注意 cin 读取字符串时会自动跳过前导空格,但如果需要处理整行输入(含空格),请使用 getline。若要去除前导零,将参数 " " 改为 "0" 即可。
提取和拼接子串
#include <iostream>
#include <string>
using namespace std;
int main(void) {
string s = "hello , world";
string s1 = s.substr(0, 5);
string s2 = s.substr(6);
string s3 = s1 + s2;
cout << s1 << s2 << "\n";
cout << s3;
}
substr 是截取子串的成员函数,参数分别为起始位置和长度(省略长度则截取至末尾)。
一些常用的 C++ 操作
C++ sort 排序函数的用法
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
bool comp(int& a, int& b) {
return a > b;
}
int main(void) {
int a[1000] = {0, 1, 1, 4, 5, 1, 4};
sort(a + 1, a + 1 + 6);
for (int i = 1; i <= 6; i++) cout << a[i];
cout << "\n";
sort(a + 1, a + 1 + 6, comp);
for (int i = 1; i <= 6; i++) cout << a[i];
}
std::sort 时间复杂度为 O(nlogn),远快于冒泡排序。自定义比较函数 comp 中使用了引用传递 & 以避免数值复制,虽然不加也能运行,但在大数据量下建议加上。
数组去重
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(void) {
int a[1000] = {0, 1, 1, 4, 5, 1, 4};
sort(a + 1, a + 1 + 6);
int* pos = unique(a + 1, a + 1 + 6);
int new_count = pos - (a + 1);
for (int i = 1; i <= new_count; i++) cout << a[i] << " ";
}
unique 会将重复元素移到末尾,并不真正删除,因此需要结合 end() 或计算新长度来使用。
二分查找
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main(void) {
int a[105];
for (int i = 1; i <= 100; i++) a[i] = i;
int* lb1 = lower_bound(a + 1, a + 101, 25);
int index1 = lb1 - a;
cout << "elem is " << *(lb1) << " index is " << index1 << endl;
int* ub2 = upper_bound(a + 1, a + 101, 25);
int index2 = ub2 - a;
cout << "elem is " << *(ub2) << " index is " << index2 << endl;
int* result = lower_bound(a + 1, a + 101, 101);
if (result == a + 101) {
cout << "lower_bound(101) return a+101\n";
}
return 0;
}
lower_bound 返回第一个不小于目标值的迭代器,upper_bound 返回第一个大于目标值的迭代器。若返回值为数组末尾,说明未找到或超出范围。
STL 容器相关
常见的 STL 容器使用
常见队列
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int main(void) {
queue<int> q;
for (int i = 0; i < 10; i++) q.push(i);
while (!q.empty()) {
cout << q.front() << " " << q.back() << "\n";
q.pop();
}
deque<int> qu;
for (int i = 0; i < 10; i++) {
qu.push_back(i);
}
while (!qu.empty()) {
cout << qu.front() << " " << qu.back() << "\n";
qu.pop_back();
qu.pop_front();
}
}
队列基于先进先出(FIFO)思想,内部通常由数组实现,上述操作时间复杂度均为 O(1)。若已引入 using namespace std;,可省略 std:: 前缀。
栈
#include <algorithm>
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
using namespace std;
int main(void) {
stack<int> s;
for (int i = 0; i < 10; i++) s.push(i);
while (!s.empty()) {
cout << s.top() << " ";
s.pop();
}
}
栈遵循先进后出(FILO)原则,操作接口与队列类似,主要区别在于访问和移除元素的顺序。
map(键值对)
Map 即字典,通过键映射值,底层通常为红黑树,插入复杂度 O(logn)。
#include <algorithm>
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include <map>
using namespace std;
int main(void) {
map<int, int> mp;
int temp = 114514;
for (int i = 0; i < 10; i++) {
if (i < 4) mp[i] = temp * (10 - i);
else mp.insert({i, temp * (10 - i)});
}
for (auto& [key, value] : mp) {
cout << "mp[" << key << "] = " << value << "\n";
}
if (mp.find(2) != mp.end()) cout << "Yes";
if (mp.find(10) == mp.end()) cout << "No";
cout << "\n";
int idx = 0;
while (1) {
mp.erase(idx);
idx++;
if (mp.empty()) {
cout << "已弹出所有元素";
break;
}
}
return 0;
}
基础操作包括插入、删除、遍历和查找。还有一种 unordered_map,底层为哈希表,查找插入速度为 O(1),但无序。
set(集合)
Set 类似于只有一个 value 的 Map,自动有序且去重,时间复杂度与 Map 一致。
#include <algorithm>
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
using namespace std;
int main(void) {
set<int> s;
for (int i = 0; i < 100; i++) s.insert(0);
s.insert(5);
s.insert(3);
s.insert(114514);
for (auto i : s) cout << i << " ";
cout << "\n";
if (s.find(3) != s.end()) cout << "Yes" << " ";
if (s.find(6) == s.end()) cout << "No" << " ";
cout << "\n";
cout << s.size() << "\n";
for (auto i : s) s.erase(i);
cout << s.size() << "\n";
return 0;
}
C++ 进阶相关
标准输入输出加快
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
lambda 表达式
std::vector<int> arr = {1, 1, 4, 5, 1, 4};
std::sort(arr.begin(), arr.end(), [](int& a, int& b) { return a > b; });
Lambda 允许直接在调用处定义匿名函数,常用于排序比较逻辑。
优先队列自定义排序
struct Node {
int x, y;
bool operator<(Node &a) const {
return x < a.x;
};
};
int main(void) {
std::priority_queue<Node> q;
}
结构体无法直接比较大小,需重载 operator<。优先队列(堆)内部为二叉搜索树,插入弹出复杂度 logn,默认取最大元素。
stringstream 流
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int main(void) {
string s = "1 2 3 4 5 6";
vector<int> arr;
stringstream stream(s);
int num;
while (stream >> num) {
arr.push_back(num);
}
for (auto i : arr) cout << i << " ";
cout << "\n";
string data = "apple,banana,orange,grape";
stringstream ss(data);
string fruit;
while (getline(ss, fruit, ',')) cout << fruit << endl;
return 0;
}
stringstream 可用于字符串与数字间的转换,或按分隔符解析字符串。
结语
以上内容属于 C++ 基础范畴。若从事 C++ 行业,这是基本功;若仅参与算法竞赛,以上技巧也足以应对大部分题目。即便只是简单练习,掌握这些编码规范也能显著提升开发效率。
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
- Markdown转HTML
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
- HTML转Markdown
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
- JSON 压缩
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online