C++入门指南

C++ STL 全面入门指南

STL 是 C++ 中强大且广泛使用的一部分,包含许多 常用数据结构算法工具,可以大大简化开发过程。

STL 大致分为三大部分:

  1. 容器 Containers:数据结构
  2. 算法 Algorithms:排序、查找、修改等
  3. 迭代器 Iterators:容器和算法之间的桥梁

容器 Containers

容器就是用来“装”数据的,我们常用的有两大类:

顺序容器(元素按插入顺序存储):

容器 特点
vector 动态数组,支持随机访问,常用
deque 双端队列,支持头尾插入删除
list 双向链表,插入/删除效率高,不支持随机访问
array 固定大小的数组(C++11 引入)
forward_list 单向链表(C++11 引入)

关联容器(基于平衡二叉树,元素自动排序):

容器 特点
set 元素唯一,自动排序
multiset 元素可重复,自动排序
map 键值对(key-value),key 唯一
multimap 键值对,key 可重复

无序关联容器(基于哈希表,查找快):

容器 特点
unordered_set 元素唯一,哈希结构
unordered_map 键值对,key 唯一,哈希结构
unordered_multiset / unordered_multimap 对应支持重复元素

动态数组 vector

常用操作:

操作 说明 示例
定义 空:vector<int> v; 初始值:vector<int> v(5, 0); 长度5,全部是0
添加元素 push_back(x) 尾部加元素
删除元素 pop_back() 删除最后一个元素
获取大小 size() 返回当前元素个数
下标访问 v[i]at(i) at(i) 有边界检查
清空 clear() 全部删掉
插入 insert(it, val) 在指定位置插入
删除 erase(it) / erase(beg, end) 删除一个或一段元素
排序 sort(v.begin(), v.end()) 从小到大排序
反转 reverse(v.begin(), v.end()) 翻转整个 vector
查找 find(v.begin(), v.end(), x) 需要 #include <algorithm>

示例代码:

#include <bits/stdc++.h>
using namespace std;
int main(){
    vector<int> vec(10,0); //指定长度为10,默认值为0的vector // 0000000000
    for(int num:vec){ //遍历
        cout << num; 
    }
    cout << endl;
    vec.push_back(2); //尾接 // 00000000002
    vec.pop_back(); //尾删除 // 0000000000
    vector<vector<int>> mat(100,vector<int>(100,0)); //构造二维vector

    cout << "vec的长度:" << vec.size() << endl; //vec的长度:10
    vec.clear(); //清空vector
    cout << "vec的长度:" << vec.size() << endl; //vec的长度:0

    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);

    cout << "尾部元素" << vec.back() << endl;
    return 0;
}

栈 stack

“栈”的抽象数据结构定义 —— 后进先出(LIFO)。

#include <bits/stdc++.h>
using namespace std;
int main(){
    stack<int> stk;
    stk.push(1); //入栈
    stk.push(2);
    stk.push(3);
    stk.push(4);
    int top = stk.top(); //取栈顶
    cout << "top: "<< top<< endl; //打印
    stk.pop(); //出栈
    top = stk.top(); //取栈顶
    cout << "top: "<< top<< endl; //打印
    return 0;
}

队列 queue

“队列”的抽象数据结构定义 —— 先进先出(FIFO)。

常用方法:

作用 用法 示例
构造 queue<类型> que queue<int> que;
进队 .push(元素) que.push(1);
出队 .pop() que.pop();
取队首 .front() int a = que.front();
取队尾 .back() int a = que.back();
查看大小 / 清空 / 判空
#include <bits/stdc++.h>
using namespace std;
int main(){
  queue<int> que;
  que.push(1);
  que.push(2);
  que.push(3);
  cout << "队首" << que.front() << endl; //队首1
  cout << "队尾" << que.back() << endl; //队尾3

  que.pop(); //出队,队头元素1出队
  cout << "队尾" << que.front() << endl; //队首2
  return 0;
}

优先队列 priority_queue

优先队列和普通队列不同,普通队列是先进先出(FIFO),但优先队列每次取出的都是“最大(或最小)”的元素,按照优先级排序。

常用方法:

方法 说明
push(x) 插入元素 x
pop() 删除优先级最高的元素
top() 返回优先级最高的元素
empty() 判断是否为空
size() 返回元素个数

堆是一种非线性结构,可以把堆看作一棵二叉树,也可以看作一个数组,即:堆就是利用完全二叉树的结构来维护的一维数组

堆可以分为大顶堆和小顶堆。

  • 大顶堆:每个结点的值都大于或等于其左右孩子结点的值。
  • 小顶堆:每个结点的值都小于或等于其左右孩子结点的值。

默认用法:大顶堆

#include <bits/stdc++.h>
using namespace std;
int main(){
  priority_queue<int> pq;
  pq.push(5); //插入元素
  pq.push(1);
  pq.push(10);
  cout << "top: " << pq.top() << endl; //输出最大元素 10
  pq.pop(); //弹出最大元素
  cout << "top: " << pq.top() << endl; //输出最大元素 5
  return 0;
}

自定义用法:小顶堆

#include <bits/stdc++.h>
using namespace std;
int main(){
  priority_queue<int,vector<int>,greater<int>> pq; //小顶堆
  pq.push(5);
  pq.push(1);
  pq.push(10);

  cout << pq.top() << endl; // 输出最小元素:1
  pq.pop();
  cout << pq.top() << endl; // 现在最小是:5
  return 0;
}

集合 set

定义:set是一个不允许元素重复的有序容器,底层使用的是红黑树来实现的,自动保持元素的有序性。

基本特性:

特性 描述
元素唯一 自动去重(底层基于红黑树)
有序排列 元素总是从小到大排序(默认)
支持快速查找 时间复杂度 O(log n)
插入删除快 时间复杂度 O(log n)
不支持下标访问 因为它是基于树,不是数组

常用方法:

方法 说明
s.insert(x) 插入元素,自动排序、去重
s.find(x) 返回迭代器,如果找不到是 s.end()``
s.erase(x) 删除值为 x 的元素
empty() 判断是否为空
for (int x : s) 从小到大
s.size() 元素个数

示例代码:

#include <bits/stdc++.h>
using namespace std;
int main(){
  set<int> s;
  //插入元素
  s.insert(5);
  s.insert(2);
  s.insert(5); //重复插入,不会生效

  //遍历输出
  for(int x : s){
    cout << x << " ";
  }
  cout << endl; // 输出:2 5

  //查找元素
  if(s.find(2) != s.end()){
    cout << "找到了元素2" << endl;
  }

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

  //判断是否为空
  if(s.empty()) cout << "集合为空" << endl;
  return 0;
}

三种集合的区别:

集合三要素 解释 set multiset unordered_set
确定性 一个元素要么在集合中,要么不在
互异性 一个元素仅可以在集合中出现一次 ❌(任意次)
无序性 集合中的元素是没有顺序的 ❌(从小到大) ❌(从小到大)

映射 map

map是一种关联容器,他存储的是键值对,并且key是唯一的,自动按顺序排序。

常用方法:

操作 用法 说明
插入 m[key] = valueinsert({key, value}) 有则改,无则加
访问值 m[key] 直接访问,若 key 不存在会自动创建并赋默认值
查找 m.find(key) 返回迭代器
删除 m.erase(key)m.erase(it) 根据 key 或迭代器删
遍历 for (auto p : m) 从小到大按 key 遍历
大小 m.size() 元素对数
清空 m.clear() 清空整个 map

示例代码:

#include <bits/stdc++.h>
using namespace std;
int main(){
  map<string,int> score;
  // 插入元素,两种方式
  score["Alice"] = 90;
  score.insert({"Bob",85});

  //修改值
  score["Bob"] = 88;

  //访问元素
  cout << "Alice: " << score["Alice"] << endl;

  //遍历map
  for(auto p : score){
    cout << p.first << " 分数是 " << p.second << endl;
  }

  //查找key是否存在
  if (score.find("Charlie") == score.end()) {
    cout << "Charlie 不存在" << endl;
  }
  return 0;
}

三种map的区别:

容器 是否排序 是否去重 底层结构 查找效率
map ✅ 有序 ✅ key 唯一 红黑树 O(log n)
unordered_map ❌ 无序 ✅ key 唯一 哈希表 O(1) 平均
multimap ✅ 有序 ❌ key 可重复 红黑树 O(log n)

map统计单词频率的案例

#include <bits/stdc++.h>
using namespace std;
int main(){
	map<string,int> wordCount;
	string word;
	cout << "Enter words (Ctrl+D/Ctrl+Z to end):" << endl;
	while(cin>>word){
		wordCount[word]++;
	}
	for(const auto& pair : wordCount){
		cout << pair.first << ": " << pair.second << endl;
	}
	return 0;
} 

字符串 string

在 C++ 中,string 是一个 标准库中的类(属于 头文件),用来表示字符串对象,支持各种操作(拼接、查找、切片、比较等等)。

操作 示例 说明
创建字符串 string s = "abc"; 初始化字符串
拼接 s1 + s2 合并字符串
获取长度 s.size()s.length() 返回字符串长度
访问字符 s[i] 类似数组,访问第 i 个字符
添加字符 s.push_back('x') 在末尾加一个字符
删除字符 s.pop_back() 删除最后一个字符
截取字符串 s.substr(pos, len) 从 pos 开始截取 len 个字符
查找字符串 s.find("abc") 返回子串起始下标,找不到返回 string::npos
替换 s.replace(pos, len, "new") 替换部分内容
清空 s.clear() 清空字符串
判断是否为空 s.empty() 判断字符串是否为空

示例代码:

#include <bits/stdc++.h>
using namespace std;
int main(){
  string s1; //构造字符串,为空
  string s2 = "qwe"; //构造字符串,并赋值qwe
  string s3(10,'6'); // 构造字符串,通过构造函数构造为6666666666
  cout << s3 << endl;
  string s = "HelloWorld";
  // 取前5个字符
  string sub = s.substr(0, 5); // Hello

  // 查找字符
  int pos = s.find("World"); // pos = 5

  // 替换字符
  s.replace(5, 5, "CPP"); // HelloCPP

  cout << s << endl; // HelloCPP


  return 0;
}

二元组 pair

pair 是一个模板类,用来将两个值打包成一个组合,就像一对搭档一样

示例代码:

#include <bits/stdc++.h>
using namespace std;
int main(){
  pair<string,int> p = {"Apple",1};
  cout << p.first << ", " << p.second << endl; //Apple, 1
  return 0;
}

📦常用方法:

操作 说明 示例
创建 定义一个 pair pair<int, string> p(1, "hi");
快速构造 使用 make_pair auto p = make_pair(2, "hello");
访问元素 .first.second p.first, p.second
赋值/比较 可以用 ==, < 等运算符 p1 < p2 按 first 比,若相等再比 second

算法 Algorithms

STL 提供了超过 60 种常用算法,常用的有:

  • 排序:sort(), stable_sort()
  • 查找:find(), binary_search()
  • 统计:count(), accumulate()
  • 修改:reverse(), rotate(), remove()

比如对一个 vector 排序:

#include <algorithm>
#include <vector>

std::vector<int> v = {5, 3, 1, 4, 2};
std::sort(v.begin(), v.end());  // 升序排序

二分查找函数

🔍 简单一句话:

函数名 功能
lower_bound() 返回第一个 ≥ 某个值的位置
upper_bound() 返回第一个 > 某个值的位置

📈 举个例子:

对于数组:[1, 2, 4, 4, 4, 7, 9]

查找值 lower_bound 位置 upper_bound 位置
4 第一个 ≥ 4 的位置 = 下标 2 第一个 > 4 的位置 = 下标 5
3 下标 2 下标 2
10 下标 7(末尾) 下标 7

统计某个数字出现次数的示例:

#include <iostream>
#include <vector>
#include <algorithm> // 引入 lower_bound 和 upper_bound
using namespace std;

int main() {
    vector<int> v = {1, 2, 4, 4, 4, 7, 9};
    int x = 4;
    int count = upper_bound(v.begin(), v.end(), x) - lower_bound(v.begin(), v.end(), x);
    cout << x << " 出现了 " << count << " 次。" << endl;
    return 0;
}

next_permutation

C++STL中的全排列函数为两个:next_permutation和prev_permutation,其中:next_permutation实现升序,而prev_permutation实现降序

next_permutation 需要初始数组是字典序最小的排列,才能生成所有字典序的全排列。如果数组的初始排列不是字典序最小的,某些排列可能会被跳过。

使用示例:

#include <bits/stdc++.h>
using namespace std;

int main() {
    vector<int> nums = {1, 2, 3};

    do {
        for (int num : nums) cout << num << " ";
        cout << endl;
    } while (next_permutation(nums.begin(), nums.end()));

    return 0;
}

输出:

1 2 3 
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

迭代器 Iterators

迭代器是 STL 的灵魂,像指针一样访问容器中的元素。

常见类型有:

  • begin():指向容器起始位置
  • end():指向容器最后一个元素的下一个位置
  • rbegin() / rend():反向迭代器
  • cbegin() / cend():常量迭代器(不可修改值)

一个简单的例子:

#include <bits/stdc++.h>
using namespace std;
int main(){
  vector<int> vec = {1,2,3,4,5};
  // 定义一个迭代器
  vector<int>::iterator it;

  for(it = vec.begin();it!=vec.end();it++){
    cout << *it << " "; //解引用访问值
  }
  // 1 2 3 4 5
  return 0;
}

💡 从 C++11 开始你可以偷懒写:

#include <bits/stdc++.h>
using namespace std;
int main(){
  vector<int> vec = {1,2,3,4,5};
  for(auto it = vec.begin();it!=vec.end();it++){
    cout << *it << " "; //解引用访问值
  }
  // 1 2 3 4 5
  return 0;
}
posted @ 2025-04-28 23:36  海浪博客  阅读(68)  评论(0)    收藏  举报