算法竞赛C++语言基础:从C到C++的完整指南
本文系统讲解算法竞赛中必备的C/C++语言基础知识,包括C语言核心语法、从C到C++的进阶,以及STL标准模板库的使用技巧。
📚 目录
C语言基础语法
从C到C++的转变
C++ STL标准模板库
算法竞赛常用技巧
1️⃣ C语言基础语法 1.1 基本数据类型 整型类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <stdio.h> #include <limits.h> int main () { char c = 'A' ; unsigned char uc = 255 ; short s = 32767 ; unsigned short us = 65535 ; int i = 2147483647 ; unsigned int ui = 4294967295U ; long l = 2147483647L ; long long ll = 9223372036854775807LL ; printf ("int范围: %d ~ %d\n" , INT_MIN, INT_MAX); printf ("long long范围: %lld ~ %lld\n" , LLONG_MIN, LLONG_MAX); return 0 ; }
浮点类型 1 2 3 4 5 6 7 8 9 10 11 12 #include <stdio.h> int main () { float f = 3.14159f ; double d = 3.14159265358979 ; long double ld = 3.14159265358979323846L ; printf ("float: %.7f\n" , f); printf ("double: %.15lf\n" , d); return 0 ; }
1.2 输入输出 标准输入输出 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <stdio.h> int main () { int a, b; scanf ("%d %d" , &a, &b); printf ("a = %d, b = %d\n" , a, b); printf ("a + b = %d\n" , a + b); printf ("%5d\n" , 123 ); printf ("%-5d\n" , 123 ); printf ("%05d\n" , 123 ); printf ("%.2f\n" , 3.1415 ); return 0 ; }
字符串输入输出 C语言中的字符串是什么?
字符串就是字符的数组,例如”Hello”就是{‘H’,’e’,’l’,’l’,’o’,’\0’}
⚠️ 注意末尾有个’\0’(空字符),表示字符串结束!
声明时要多留一个位置给’\0’,例如存5个字符要char str[6]
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 #include <stdio.h> #include <string.h> int main () { char str1[100 ]; char str2[100 ]; printf ("输入一个单词: " ); scanf ("%s" , str1); getchar(); printf ("输入一行文本: " ); fgets(str2, sizeof (str2), stdin ); str2[strcspn (str2, "\n" )] = '\0' ; printf ("你输入的单词: %s\n" , str1); printf ("你输入的一行: %s\n" , str2); return 0 ; }
新手常见问题❓
Q1: 为什么scanf读字符串不加&?
1 2 3 4 5 char str[100 ];scanf ("%s" , str); int x;scanf ("%d" , &x);
因为数组名str本身就代表数组的首地址
而变量x需要用&x才能取到地址
简单记忆:数组不加&,普通变量加&
Q2: scanf读字符串后为什么要getchar()?
1 2 3 scanf ("%s" , str1);getchar(); fgets(str2, 100 , stdin );
scanf读完后,输入缓冲区还剩一个’\n’
如果直接用fgets,会把’\n’当作一行读入
所以要用getchar()把’\n’消耗掉
Q3: 什么时候用scanf,什么时候用fgets?
读单个单词 → 用scanf("%s", str)
读一整行(可能有空格) → 用fgets(str, size, stdin)
读多个单词 → 用scanf("%s%s%s", s1, s2, s3)
1.3 控制结构
老师说 :程序不是从上到下直直地跑,而是会”思考”(判断)和”重复”(循环)。这就像你做题:先判断题型,再重复计算步骤!
条件语句 什么是条件语句?
让程序根据不同情况做不同的事
就像生活中的”如果…那么…”
例如:如果下雨,那么带伞;否则,不带伞
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 39 40 41 42 43 44 45 46 #include <stdio.h> int main () { int score; scanf ("%d" , &score); if (score >= 90 ) { printf ("优秀\n" ); } else if (score >= 80 ) { printf ("良好\n" ); } else if (score >= 60 ) { printf ("及格\n" ); } else { printf ("不及格\n" ); } int a = 10 , b = 20 ; int max = (a > b) ? a : b; char grade; scanf (" %c" , &grade); switch (grade) { case 'A' : printf ("优秀\n" ); break ; case 'B' : printf ("良好\n" ); break ; case 'C' : printf ("及格\n" ); break ; default : printf ("不及格\n" ); } return 0 ; }
条件表达式技巧:
1 2 3 4 5 6 7 8 if (x > 0 && x < 10 ) { } if (x < 0 || x > 10 ) { } if (!(x == 0 )) { } if (a != 0 && b / a > 1 ) { } if (a == 0 || b / a > 1 ) { }
新手常见错误❌
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 if (x = 5 ) { } if (x == 5 ) { } switch (x) { case 1 : printf ("A\n" ); case 2 : printf ("B\n" ); case 3 : printf ("C\n" ); } switch (x) { case 1 : printf ("A\n" ); break ; case 2 : printf ("B\n" ); break ; case 3 : printf ("C\n" ); break ; }
循环语句 什么是循环?
重复执行一段代码,直到满足退出条件
就像你抄10遍课文,不用写10次代码,用循环1次就搞定!
算法题中90%的代码都需要循环
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 39 40 41 42 43 44 45 46 47 48 49 #include <stdio.h> int main () { for (int i = 0 ; i < 10 ; i++) { printf ("%d " , i); } printf ("\n" ); int i = 0 ; while (i < 10 ) { printf ("%d " , i); i++; } printf ("\n" ); i = 0 ; do { printf ("%d " , i); i++; } while (i < 10 ); printf ("\n" ); for (int i = 0 ; i < 10 ; i++) { if (i == 5 ) continue ; if (i == 8 ) break ; printf ("%d " , i); } printf ("\n" ); return 0 ; }
三种循环的选择:
循环类型
适用场景
示例
for
知道循环次数
遍历数组、计数
while
不知道循环次数
读到文件末尾、等待条件
do-while
至少执行一次
菜单显示、输入验证
实战案例: 求1到100的和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int sum = 0 ;for (int i = 1 ; i <= 100 ; i++) { sum += i; } printf ("sum = %d\n" , sum); int sum = 0 , i = 1 ;while (i <= 100 ) { sum += i; i++; } printf ("sum = %d\n" , sum);
新手常见错误❌
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 for (int i = 0 ; i < 10 ; ) { printf ("%d " , i); } for (int i = 0 ; i <= 10 ; i++) { } switch (x) { case 1 : continue ; }
1.4 数组 一维数组 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 #include <stdio.h> #include <string.h> int main () { int arr1[5 ] = {1 , 2 , 3 , 4 , 5 }; int arr2[5 ] = {1 , 2 }; int arr3[5 ] = {0 }; for (int i = 0 ; i < 5 ; i++) { printf ("%d " , arr1[i]); } printf ("\n" ); void printArray (int arr[], int n) ; printArray(arr1, 5 ); return 0 ; } void printArray (int arr[], int n) { for (int i = 0 ; i < n; i++) { printf ("%d " , arr[i]); } printf ("\n" ); }
二维数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <stdio.h> int main () { int matrix[3 ][4 ] = { {1 , 2 , 3 , 4 }, {5 , 6 , 7 , 8 }, {9 , 10 , 11 , 12 } }; for (int i = 0 ; i < 3 ; i++) { for (int j = 0 ; j < 4 ; j++) { printf ("%3d " , matrix[i][j]); } printf ("\n" ); } return 0 ; }
1.5 函数 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 #include <stdio.h> int add (int a, int b) ;void swap (int *a, int *b) ; int max (int a, int b) ;int main () { int x = 10 , y = 20 ; int sum = add(x, y); printf ("sum = %d\n" , sum); swap(&x, &y); printf ("x = %d, y = %d\n" , x, y); return 0 ; } int add (int a, int b) { return a + b; } void swap (int *a, int *b) { int temp = *a; *a = *b; *b = temp; } int max (int a, int b) { return (a > b) ? a : b; }
递归函数 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 #include <stdio.h> int factorial (int n) { if (n <= 1 ) return 1 ; return n * factorial(n - 1 ); } int fibonacci (int n) { if (n <= 1 ) return n; return fibonacci(n - 1 ) + fibonacci(n - 2 ); } int gcd (int a, int b) { if (b == 0 ) return a; return gcd(b, a % b); } int main () { printf ("5! = %d\n" , factorial(5 )); printf ("fib(10) = %d\n" , fibonacci(10 )); printf ("gcd(48, 18) = %d\n" , gcd(48 , 18 )); return 0 ; }
1.6 指针 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 #include <stdio.h> int main () { int x = 10 ; int *p = &x; printf ("x的值: %d\n" , x); printf ("x的地址: %p\n" , &x); printf ("p的值(x的地址): %p\n" , p); printf ("p指向的值: %d\n" , *p); *p = 20 ; printf ("修改后x的值: %d\n" , x); int arr[5 ] = {1 , 2 , 3 , 4 , 5 }; int *ptr = arr; for (int i = 0 ; i < 5 ; i++) { printf ("%d " , *(ptr + i)); } printf ("\n" ); return 0 ; }
1.7 结构体 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 39 40 41 42 43 44 #include <stdio.h> #include <string.h> struct Student { int id; char name[50 ]; float score; }; int main () { struct Student s1 = {1 , "张三" , 95.5 }; printf ("学号: %d\n" , s1.id); printf ("姓名: %s\n" , s1.name); printf ("成绩: %.1f\n" , s1.score); s1.score = 98.0 ; strcpy (s1.name, "李四" ); struct Student *p = &s1; printf ("通过指针访问: %d, %s, %.1f\n" , p->id, p->name, p->score); struct Student students [3] = { {1 , "张三" , 95.5 }, {2 , "李四" , 88.0 }, {3 , "王五" , 92.3 } }; for (int i = 0 ; i < 3 ; i++) { printf ("%d: %s - %.1f\n" , students[i].id, students[i].name, students[i].score); } return 0 ; }
2️⃣ 从C到C++的转变 2.1 命名空间(namespace) 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 #include <iostream> using namespace std;namespace MySpace { int x = 10 ; void print () { cout << "MySpace::print()" << endl; } } int main () { using namespace std; cout << "Hello C++" << endl; cout << MySpace::x << endl; MySpace::print (); using MySpace::x; cout << x << endl; return 0 ; }
2.2 输入输出流 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <iostream> #include <iomanip> using namespace std;int main () { int a, b; cin >> a >> b; cout << "a = " << a << ", b = " << b << endl; double pi = 3.14159265358979 ; cout << fixed << setprecision (2 ) << pi << endl; cout << setw (10 ) << 123 << endl; cout << left << setw (10 ) << 123 << endl; cout << setfill ('0' ) << setw (5 ) << 123 << endl; return 0 ; }
2.3 引用(Reference) 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 #include <iostream> using namespace std;void swap (int &a, int &b) { int temp = a; a = b; b = temp; } int & getElement (int arr[], int index) { return arr[index]; } int main () { int x = 10 , y = 20 ; int &ref = x; cout << "x = " << x << ", ref = " << ref << endl; ref = 30 ; cout << "x = " << x << endl; swap (x, y); cout << "交换后: x = " << x << ", y = " << y << endl; int arr[5 ] = {1 , 2 , 3 , 4 , 5 }; getElement (arr, 2 ) = 100 ; cout << "arr[2] = " << arr[2 ] << endl; return 0 ; }
引用 vs 指针:
特性
引用
指针
语法
int &ref = x
int *ptr = &x
初始化
必须初始化
可以不初始化
重新绑定
不能改变引用对象
可以指向其他对象
空值
不能为空
可以为NULL/nullptr
使用
直接使用
需要解引用*
2.4 函数重载 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <iostream> using namespace std;int add (int a, int b) { return a + b; } double add (double a, double b) { return a + b; } int add (int a, int b, int c) { return a + b + c; } int main () { cout << add (1 , 2 ) << endl; cout << add (1.5 , 2.5 ) << endl; cout << add (1 , 2 , 3 ) << endl; return 0 ; }
2.5 默认参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <iostream> using namespace std;void print (int a, int b = 10 , int c = 20 ) { cout << "a = " << a << ", b = " << b << ", c = " << c << endl; } int main () { print (1 ); print (1 , 2 ); print (1 , 2 , 3 ); return 0 ; }
2.6 内联函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <iostream> using namespace std;inline int max (int a, int b) { return (a > b) ? a : b; } inline int min (int a, int b) { return (a < b) ? a : b; } int main () { cout << max (10 , 20 ) << endl; cout << min (10 , 20 ) << endl; return 0 ; }
内联函数 vs 宏定义:
内联函数有类型检查,更安全
内联函数可以调试
宏定义是简单的文本替换
2.7 新的类型转换 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <iostream> using namespace std;int main () { double d = 3.14 ; int i = static_cast <int >(d); const int x = 10 ; int *p = const_cast <int *>(&x); long addr = reinterpret_cast <long >(p); cout << "i = " << i << endl; cout << "addr = " << addr << endl; return 0 ; }
3️⃣ C++ STL标准模板库 3.1 vector(动态数组) 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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #include <iostream> #include <vector> #include <algorithm> using namespace std;int main () { vector<int > v1; vector<int > v2 (5 ) ; vector<int > v3 (5 , 10 ) ; vector<int > v4 = {1 , 2 , 3 , 4 , 5 }; v1. push_back (1 ); v1. push_back (2 ); v1. push_back (3 ); cout << "v1[0] = " << v1[0 ] << endl; cout << "v1.front() = " << v1.f ront() << endl; cout << "v1.back() = " << v1. back () << endl; cout << "size: " << v1. size () << endl; cout << "capacity: " << v1. capacity () << endl; cout << "empty: " << v1. empty () << endl; for (int i = 0 ; i < v1. size (); i++) { cout << v1[i] << " " ; } cout << endl; for (int x : v1) { cout << x << " " ; } cout << endl; for (vector<int >::iterator it = v1. begin (); it != v1. end (); it++) { cout << *it << " " ; } cout << endl; v1. pop_back (); v1. erase (v1. begin ()); v1. clear (); vector<int > v = {3 , 1 , 4 , 1 , 5 , 9 , 2 , 6 }; sort (v.begin (), v.end ()); reverse (v.begin (), v.end ()); auto it = find (v.begin (), v.end (), 5 ); if (it != v.end ()) { cout << "找到5,位置: " << it - v.begin () << endl; } return 0 ; }
vector常用函数总结:
函数
功能
时间复杂度
push_back(x)
尾部添加元素
O(1)均摊
pop_back()
删除尾部元素
O(1)
size()
返回元素个数
O(1)
empty()
判断是否为空
O(1)
clear()
清空所有元素
O(n)
front()
返回第一个元素
O(1)
back()
返回最后一个元素
O(1)
insert(it, x)
在it处插入x
O(n)
erase(it)
删除it处的元素
O(n)
3.2 string(字符串) 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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 #include <iostream> #include <string> #include <algorithm> using namespace std;int main () { string s1 = "Hello" ; string s2 ("World" ) ; string s3 (5 , 'A' ) ; string s = s1 + " " + s2; cout << s << endl; cout << s[0 ] << endl; cout << s.front () << endl; cout << s.back () << endl; cout << "length: " << s.length () << endl; cout << "size: " << s.size () << endl; string sub = s.substr (0 , 5 ); cout << "substr: " << sub << endl; size_t pos = s.find ("World" ); if (pos != string::npos) { cout << "找到World,位置: " << pos << endl; } s.replace (0 , 5 , "Hi" ); cout << s << endl; s.insert (2 , "XXX" ); s.erase (2 , 3 ); string str = "Hello World" ; transform (str.begin (), str.end (), str.begin (), ::tolower); cout << str << endl; transform (str.begin (), str.end (), str.begin (), ::toupper); cout << str << endl; string a = "abc" , b = "abd" ; cout << (a < b) << endl; int num = stoi ("123" ); double d = stod ("3.14" ); string numStr = to_string (456 ); return 0 ; }
3.3 stack(栈) 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 #include <iostream> #include <stack> using namespace std;int main () { stack<int > stk; stk.push (1 ); stk.push (2 ); stk.push (3 ); cout << "top: " << stk.top () << endl; stk.pop (); cout << "top after pop: " << stk.top () << endl; cout << "size: " << stk.size () << endl; cout << "empty: " << stk.empty () << endl; while (!stk.empty ()) { cout << stk.top () << " " ; stk.pop (); } cout << endl; return 0 ; }
应用:括号匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 bool isValid (string s) { stack<char > stk; for (char c : s) { if (c == '(' || c == '[' || c == '{' ) { stk.push (c); } else { if (stk.empty ()) return false ; char top = stk.top (); if ((c == ')' && top == '(' ) || (c == ']' && top == '[' ) || (c == '}' && top == '{' )) { stk.pop (); } else { return false ; } } } return stk.empty (); }
3.4 queue(队列) 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 #include <iostream> #include <queue> using namespace std;int main () { queue<int > q; q.push (1 ); q.push (2 ); q.push (3 ); cout << "front: " << q.front () << endl; cout << "back: " << q.back () << endl; q.pop (); cout << "front after pop: " << q.front () << endl; cout << "size: " << q.size () << endl; cout << "empty: " << q.empty () << endl; while (!q.empty ()) { cout << q.front () << " " ; q.pop (); } cout << endl; return 0 ; }
3.5 priority_queue(优先队列/堆) 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> #include <queue> #include <vector> using namespace std;int main () { priority_queue<int > maxHeap; maxHeap.push (3 ); maxHeap.push (1 ); maxHeap.push (4 ); maxHeap.push (1 ); maxHeap.push (5 ); while (!maxHeap.empty ()) { cout << maxHeap.top () << " " ; maxHeap.pop (); } cout << endl; priority_queue<int , vector<int >, greater<int >> minHeap; minHeap.push (3 ); minHeap.push (1 ); minHeap.push (4 ); minHeap.push (1 ); minHeap.push (5 ); while (!minHeap.empty ()) { cout << minHeap.top () << " " ; minHeap.pop (); } cout << endl; return 0 ; }
自定义比较:
1 2 3 4 5 6 7 8 9 10 struct Node { int value; int priority; bool operator < (const Node &other) const { return priority < other.priority; } }; priority_queue<Node> pq;
3.6 set(集合) 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 39 40 41 42 43 44 45 46 #include <iostream> #include <set> using namespace std;int main () { set<int > s; s.insert (3 ); s.insert (1 ); s.insert (4 ); s.insert (1 ); s.insert (5 ); for (int x : s) { cout << x << " " ; } cout << endl; if (s.find (3 ) != s.end ()) { cout << "找到3" << endl; } cout << "1的个数: " << s.count (1 ) << endl; s.erase (3 ); s.erase (s.begin ()); cout << "size: " << s.size () << endl; set<int > nums = {1 , 3 , 5 , 7 , 9 }; auto it1 = nums.lower_bound (5 ); auto it2 = nums.upper_bound (5 ); cout << "lower_bound(5): " << *it1 << endl; cout << "upper_bound(5): " << *it2 << endl; return 0 ; }
3.7 map(映射) 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 39 40 41 42 43 44 45 #include <iostream> #include <map> #include <string> using namespace std;int main () { map<string, int > mp; mp["apple" ] = 3 ; mp["banana" ] = 5 ; mp["orange" ] = 2 ; mp.insert ({"grape" , 4 }); cout << "apple: " << mp["apple" ] << endl; if (mp.find ("apple" ) != mp.end ()) { cout << "找到apple" << endl; } if (mp.count ("pear" ) == 0 ) { cout << "没有pear" << endl; } for (auto &p : mp) { cout << p.first << ": " << p.second << endl; } for (auto it = mp.begin (); it != mp.end (); it++) { cout << it->first << ": " << it->second << endl; } mp.erase ("banana" ); cout << "size: " << mp.size () << endl; return 0 ; }
统计字符出现次数:
1 2 3 4 5 6 7 8 9 10 string s = "hello world" ; map<char , int > cnt; for (char c : s) { cnt[c]++; } for (auto &p : cnt) { cout << p.first << ": " << p.second << endl; }
3.8 unordered_set 和 unordered_map 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 #include <iostream> #include <unordered_set> #include <unordered_map> using namespace std;int main () { unordered_set<int > us = {3 , 1 , 4 , 1 , 5 }; for (int x : us) { cout << x << " " ; } cout << endl; unordered_map<string, int > um; um["apple" ] = 3 ; um["banana" ] = 5 ; for (auto &p : um) { cout << p.first << ": " << p.second << endl; } return 0 ; }
set/map vs unordered_set/unordered_map:
特性
set/map
unordered_set/unordered_map
底层实现
红黑树
哈希表
有序性
有序
无序
查找/插入/删除
O(log n)
O(1)平均
遍历
按序
无序
3.9 pair(对组) 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 #include <iostream> #include <utility> #include <vector> #include <algorithm> using namespace std;int main () { pair<int , string> p1 (1 , "apple" ) ; pair<int , string> p2 = make_pair (2 , "banana" ); auto p3 = make_pair (3 , "orange" ); cout << p1.f irst << " " << p1. second << endl; vector<pair<int , string>> vec = { {3 , "c" }, {1 , "a" }, {2 , "b" } }; sort (vec.begin (), vec.end ()); for (auto &p : vec) { cout << p.first << " " << p.second << endl; } return 0 ; }
3.10 algorithm(算法库) 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 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <iostream> #include <vector> #include <algorithm> using namespace std;int main () { vector<int > v = {3 , 1 , 4 , 1 , 5 , 9 , 2 , 6 }; sort (v.begin (), v.end ()); sort (v.begin (), v.end (), greater <int >()); reverse (v.begin (), v.end ()); auto it = find (v.begin (), v.end (), 5 ); if (it != v.end ()) { cout << "找到5" << endl; } sort (v.begin (), v.end ()); bool found = binary_search (v.begin (), v.end (), 5 ); auto it1 = lower_bound (v.begin (), v.end (), 5 ); auto it2 = upper_bound (v.begin (), v.end (), 5 ); int maxVal = *max_element (v.begin (), v.end ()); int minVal = *min_element (v.begin (), v.end ()); int sum = accumulate (v.begin (), v.end (), 0 ); sort (v.begin (), v.end ()); v.erase (unique (v.begin (), v.end ()), v.end ()); vector<int > arr = {1 , 2 , 3 }; do { for (int x : arr) cout << x << " " ; cout << endl; } while (next_permutation (arr.begin (), arr.end ())); return 0 ; }
4️⃣ 算法竞赛常用技巧 4.1 快速输入输出 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <iostream> using namespace std;int main () { ios::sync_with_stdio (false ); cin.tie (0 ); cout.tie (0 ); int n; cin >> n; for (int i = 0 ; i < n; i++) { int x; cin >> x; cout << x << "\n" ; } return 0 ; }
4.2 常用宏定义 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 <bits/stdc++.h> using namespace std;#define ll long long #define ull unsigned long long #define pii pair<int, int> #define vi vector<int> #define vll vector<long long> #define rep(i, a, b) for(int i = (a); i < (b); i++) #define rrep(i, a, b) for(int i = (a); i >= (b); i--) #define all(x) (x).begin(), (x).end() #define sz(x) (int)(x).size() #define pb push_back #define mp make_pair const int INF = 0x3f3f3f3f ;const ll LINF = 0x3f3f3f3f3f3f3f3fLL ;const int MOD = 1e9 + 7 ;int main () { ll n; cin >> n; vi v (n) ; rep (i, 0 , n) { cin >> v[i]; } sort (all (v)); return 0 ; }
4.3 位运算技巧 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 #include <iostream> using namespace std;int main () { int x = 10 ; if (x & 1 ) cout << "奇数" << endl; else cout << "偶数" << endl; int a = x << 1 ; int b = x >> 1 ; int p = 5 , q = 7 ; p ^= q; q ^= p; p ^= q; cout << "p = " << p << ", q = " << q << endl; bool isPowerOf2 = (x > 0 ) && ((x & (x - 1 )) == 0 ); int lowbit = x & (-x); int cnt = __builtin_popcount(x); return 0 ; }
4.4 常用数学函数 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 #include <iostream> #include <cmath> #include <algorithm> using namespace std;int main () { cout << abs (-5 ) << endl; cout << __gcd(12 , 8 ) << endl; cout << pow (2 , 10 ) << endl; cout << sqrt (16 ) << endl; cout << ceil (3.2 ) << endl; cout << floor (3.8 ) << endl; int a = 5 , b = 7 ; swap (a, b); cout << max (3 , 5 ) << endl; cout << min (3 , 5 ) << endl; cout << max ({1 , 2 , 3 , 4 , 5 }) << endl; return 0 ; }
4.5 完整模板 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 #include <bits/stdc++.h> using namespace std;#define ll long long #define pii pair<int, int> #define vi vector<int> #define rep(i, a, b) for(int i = (a); i < (b); i++) #define all(x) (x).begin(), (x).end() const int MAXN = 1e5 + 5 ;const int INF = 0x3f3f3f3f ;const int MOD = 1e9 + 7 ;int n, m;int a[MAXN];void solve () { } int main () { ios::sync_with_stdio (false ); cin.tie (0 ); int t = 1 ; while (t--) { solve (); } return 0 ; }
📊 STL容器选择指南
需求
推荐容器
原因
动态数组,频繁随机访问
vector
O(1)随机访问
频繁首尾操作
deque
O(1)首尾操作
需要LIFO
stack
栈特性
需要FIFO
queue
队列特性
需要优先级
priority_queue
堆结构
有序+去重+查找
set
O(log n)操作
键值对+有序
map
O(log n)操作
去重+快速查找
unordered_set
O(1)平均查找
键值对+快速查找
unordered_map
O(1)平均查找
💡 学习建议
打好C语言基础 :指针、数组、结构体是重点
理解C++特性 :引用、重载、命名空间
熟练使用STL :至少掌握vector、string、map、set
多写代码 :理论+实践才能真正掌握
刷题巩固 :LeetCode、洛谷、Codeforces
阅读标准库文档 :cppreference.com
参加比赛 :实战是最好的老师
📚 推荐资源 在线资源
书籍推荐
《C++ Primer》- 全面系统
《STL源码剖析》- 深入理解STL
《算法竞赛入门经典》- 刘汝佳
《算法竞赛进阶指南》- 李煜东
🎯 练习题推荐 基础题
[洛谷 P1001] A+B Problem
[洛谷 P1009] 阶乘之和
[洛谷 P1014] Cantor表
[LeetCode 1] 两数之和
[LeetCode 20] 有效的括号
进阶题
[洛谷 P1sec] 排序
[LeetCode 15] 三数之和
[LeetCode 49] 字母异位词分组
[LeetCode 347] 前K个高频元素
[洛谷 P1sec] 普及组题目
💪 加油! C++是算法竞赛的利器,掌握好STL能让你的代码更简洁高效。多练习,多总结,祝你在算法竞赛中取得好成绩!
Happy Coding! 🚀