整理 C++ 基础算法核心模板代码,涵盖快速排序、归并排序、整数与浮点数二分、高精度加减乘除运算、双指针优化、位运算技巧、离散化及区间合并。内容包含算法思想解析、关键注意事项说明及完整可运行代码示例,适合算法初学者复习与竞赛准备。
极客工坊1 浏览
快速排序
思想
快排利用了分治算法,分治算法通常包含三步:
分成子问题
递归处理子问题
子问题合并
快排的操作是选取一个基准数 x,保证该数在数组中左边都比它小,右边都比它大。利用两个指针 i,j 分别放在首尾,当 i 走到第一个比 x 大的数停下,j 找到第一个比 x 小的数停下,交换位置。直到 i >= j 时,x 左边都是比它小的数,右边都是比它大的数。然后分治,将区间换成两个小区间继续操作。
模板展示
#include<iostream>usingnamespace std;
constint N = 1e6 + 10;
int a[N];
voidquick_sort(int a[], int l, int r){
if (l >= r) return;
int i = l - 1, j = r + 1;
int x = a[(l + r) >> 1];
while (i < j) {
do i++; while (a[i] < x);
do j--; while (a[j] > x);
if (i < j) swap(a[i], a[j]);
}
quick_sort(a, l, j);
quick_sort(a, j + 1, r);
}
intmain(){
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf(, &a[i]);
(a, , n - );
( i = ; i < n; i++) (, a[i]);
;
}
#include<iostream>usingnamespace std;
constint N = 1e6 + 10;
int n, q, a[N];
intmain(){
cin >> n >> q;
for (int i = 0; i < n; i++) cin >> a[i];
while (q--) {
int x;
cin >> x;
int l = 0, r = n - 1;
while (l < r) {
int mid = (l + r) >> 1;
if (a[mid] < x) l = mid + 1;
else r = mid;
}
if (a[l] != x) cout << "-1 -1" << endl;
else {
cout << l << ' ';
int l = 0, r = n - 1;
while (l < r) {
int mid = (l + r + 1) >> 1;
if (a[mid] <= x) l = mid;
else r = mid - 1;
}
cout << l << endl;
}
}
return0;
}
高精度
遇到很大的数加减乘除时用到高精度,让数存进数组,用代码实现算术运算。
高精度加法
#include<iostream>#include<vector>usingnamespace std;
vector<int> add(vector<int> &A, vector<int> &B){
vector<int> C;
int t = 0;
for (int i = 0; i < A.size() || i < B.size(); i++) {
if (i < A.size()) t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10);
t /= 10;
}
if (t) C.push_back(1);
return C;
}
intmain(){
string a, b;
vector<int> A, B;
cin >> a >> b;
for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
for (int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0');
auto C = add(A, B);
for (int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);
return0;
}
减法操作让 A 作为大数,t = A[i] - t(t 是被借走的位数),当前 a[i] 减去 t。同时利用 t 记录值,看 B 是否遍历结束,让 t -= B[i]。操作结束后 (t + 10) % 10,如果相减是负数说明借了一位,t = 1,反之为 0。
#include<iostream>#include<vector>usingnamespace std;
boolcmp(vector<int> &A, vector<int> &B){
if (A.size() != B.size()) return A.size() > B.size();
for (int i = A.size() - 1; i >= 0; i--) {
if (A[i] != B[i]) return A[i] > B[i];
}
returntrue;
}
vector<int> sub(vector<int> &A, vector<int> &B){
vector<int> C;
for (int i = 0, t = 0; i < A.size() || i < B.size(); i++) {
t = A[i] - t;
if (i < B.size()) t -= B[i];
C.push_back((t + 10) % 10);
if (t < 0) t = 1;
else t = 0;
}
while (C.back() == 0 && C.size() > 1) C.pop_back();
return C;
}
intmain(){
string a, b;
vector<int> A, B;
cin >> a >> b;
for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
for (int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0');
if (cmp(A, B)) {
auto C = sub(A, B);
for (int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);
} else {
auto C = sub(B, A);
printf("-");
for (int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);
}
return0;
}
高精度乘法
讲一个大数乘一个小数。用 t 表示值,重点是循环条件和前导零。
循环条件为 i < A.size() || t,因为 t 最后如果有进位还要继续操作。
乘法结束后如果答案是 0000,要去掉前导零变为 0。
#include<iostream>#include<vector>usingnamespace std;
vector<int> mul(vector<int>& A, int b){
vector<int> C;
for (int i = 0, t = 0; i < A.size() || t; i++) {
if (i < A.size()) t = A[i] * b + t;
C.push_back(t % 10);
t /= 10;
}
while (C.back() == 0 && C.size() > 1) C.pop_back();
return C;
}
intmain(){
string a;
int b;
cin >> a >> b;
vector<int> A;
for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
auto C = mul(A, b);
for (int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);
return0;
}
高精度除法
大数除以一个小数。用 r 作为余数,去掉前导零。
#include<iostream>#include<vector>#include<algorithm>usingnamespace std;
vector<int> div(vector<int>& A, int b, int &r){
r = 0;
vector<int> C;
for (int i = A.size() - 1; i >= 0; i--) {
r = r * 10 + A[i];
C.push_back(r / b);
r %= b;
}
reverse(C.begin(), C.end());
while (C.back() == 0 && C.size() > 1) C.pop_back();
return C;
}
intmain(){
string a;
int b;
cin >> a >> b;
vector<int> A;
for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
int r;
auto C = div(A, b, r);
for (int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);
cout << "\n" << r;
return0;
}
双指针
双指针优化 O(n^2) 算法成 O(n)。
一般形式:
for (int i = 0, j = 0; i < n; i++) {
while (j < i && check(i, j)) j++;
// 剩下的操作就是看题目要求了
}
例子:找到一段序列最长的不包含重复数字的序列。
朴素算法 O(n^2),check 判断是否有重复,i 指向序列末端,j 指向起始位置。
双指针算法:j 指向起始位置,当发现 i 位置的值出现次数 > 1,j 就移动直到 i 位置不大于 1。
#include<iostream>usingnamespace std;
constint N = 1e5 + 10;
int n, a[N], s[N], res;
intmain(){
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0, j = 0; i < n; i++) {
s[a[i]]++;
while (s[a[i]] > 1) {
s[a[j]]--;
j++;
}
res = max(res, i - j + 1);
}
cout << res;
return0;
}
#include<iostream>usingnamespace std;
intmain(){
int n;
cin >> n;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
int num = 0;
while (x) {
if (x & 1) num++;
x >>= 1;
}
cout << num << ' ';
}
return0;
}
#include<iostream>usingnamespace std;
intlowbit(int x){
return x & (-x);
}
intmain(){
int n;
cin >> n;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
int res = 0;
while (x) {
x -= lowbit(x);
res++;
}
cout << res << ' ';
}
return0;
}
#include<iostream>#include<algorithm>#include<vector>usingnamespace std;
typedef pair<int, int> PII;
constint N = 3e5;
int n, m, a[N], s[N];
vector<int> alls;
vector<PII> add, query;
intfind(int x){
int l = 0, r = alls.size() - 1;
while (l < r) {
int mid = l + r >> 1;
if (alls[mid] < x) l = mid + 1;
else r = mid;
}
return l + 1;
}
intmain(){
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
int x, c;
scanf("%d%d", &x, &c);
add.push_back({x, c});
alls.push_back(x);
}
for (int i = 0; i < m; i++) {
int l, r;
scanf("%d%d", &l, &r);
query.push_back({l, r});
alls.push_back(l);
alls.push_back(r);
}
sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());
for (auto item : add) {
int x = find(item.first);
a[x] += item.second;
}
for (int i = 1; i <= alls.size(); i++) s[i] = s[i - 1] + a[i];
for (auto item : query) {
int l = find(item.first), r = find(item.second);
cout << s[r] - s[l - 1] << endl;
}
return0;
}
区间合并
这类问题较常见,把代码看懂即可。
#include<iostream>#include<vector>#include<algorithm>usingnamespace std;
constint N = 1e5 + 10;
typedef pair<int, int> Pii;
vector<Pii> segs;
int n;
voidmerge(){
vector<Pii> res;
int st = -0x3f3f3f3f, ed = -0x3f3f3f3f;
for (auto seg : segs) {
if (ed < seg.first) {
if (ed != -0x3f3f3f3f) res.push_back({st, ed});
st = seg.first, ed = seg.second;
} else {
ed = max(ed, seg.second);
}
}
if (st != -0x3f3f3f3f) res.push_back({st, ed});
segs = res;
}
intmain(){
cin >> n;
for (int i = 0; i < n; i++) {
int l, r;
cin >> l >> r;
segs.push_back({l, r});
}
sort(segs.begin(), segs.end());
merge();
cout << segs.size();
return0;
}