一、链表
1.1 单链表
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
//head表示头结点下标 idx数组下标
int head, e[N], ne[N], idx;
void init()
{
head = -1;
idx = 0;
}
void add_to_head(int x)
{
e[idx] = x, ne[idx] = head, head = idx ++;
}
//将x插入到下标为k的点后面
void add(int k, int x)
{
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx ++;
}
void my_remove(int k)
{
ne[k] = ne[ne[k]];
}
int main()
{
int m; cin >> m;
init();
while (m -- )
{
int k, x; char op; cin >> op;
if(op == 'H')
{
cin >> x;
add_to_head(x);
}
else if(op == 'D')
{
cin >> k;
if(!k) head = ne[head];
else my_remove(k - 1);
}
else
{
cin >> k >> x;
add(k - 1, x);
}
}
for(int i = head; i != -1; i = ne[i]) cout << e[i] << ' ';
cout << endl;
return 0;
}
1.2 双链表
和单链表作比较:结构体里面的指针变成左和右。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int idx, head;
int e[N], l[N], r[N];
//在a的右边插入一个x
void insert(int a, int x)
{
e[idx] = x;
l[idx] = a, r[idx] = r[a];
l[r[a]] = idx, r[a] = idx ++;
}
void remove(int a)
{
l[r[a]] = l[a];
r[l[a]] = r[a];
}
int main()
{
int m; cin >> m;
//0左端点 1右端点
r[0] = 1, l[1] = 0;
idx = 2;
while (m -- )
{
int x, k; string op; cin >> op;
if(op == "L")
{
cin >> x;
insert(0, x);
}
else if(op == "R")
{
cin >> x;
insert(l[1], x);
}
else if(op == "D")
{
cin >> k;
remove(k + 1);
}
else if(op == "IL")
{
cin >> k >> x;
insert(l[k + 1], x);
}
else
{
cin >> k >> x;
insert(k + 1, x);
}
}
for(int i = r[0]; i != 1; i = r[i]) cout << e[i] << ' ';
return 0;
}
二、栈
2.1 表达式求值
确定符号优先级。
- 加号的前面是加号的话一定可以运算
//两个栈 一个数据一个符号
#include <bits/stdc++.h>
using namespace std;
stack<int> num;
stack<char> op;
void eval()
{
auto a = num.top(); num.pop();
auto b = num.top(); num.pop();
auto c = op.top(); op.pop();
int x;
if(c == '+') x = a + b;
else if(c == '-') x = b - a;
else if(c == '*') x = a * b;
else x = b / a;
num.push(x);
}
int main()
{
unordered_map<char, int> m{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
string s; cin >> s;
for(int i = 0; i < s.size(); ++ i)
{
auto c = s[i];
if(isdigit(c))
{
int x = 0, j = i;
while(j < s.size() && isdigit(s[j]))
x = x * 10 + s[j ++] - '0';
i = j - 1;
num.push(x);
}
else if(c == '(') op.push('(');
else if(c == ')')
{
while(op.top() != '(') eval();
op.pop();
}
else
{
while(op.size() && op.top() != '(' && m[op.top()] >= m[c]) eval();
op.push(c);
}
}
while(op.size()) eval();
cout << num.top() << endl;
return 0;
}
2.2 单调栈
以3 4 2 7 5
为例,2 比 3 小,单调栈内就不需要有 3 了。所以是个单调递增栈。
//单调递增栈
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
int main()
{
stack<int> sta;
int n; cin >> n;
vector<int> a(n);
for(int i = 0; i < n; ++ i) cin >> a[i];
for(int i = 0; i < n; ++ i)
{
if(sta.empty())
{
cout << -1 << ' ';
sta.push(a[i]);
}
else if(sta.top() < a[i])
{
cout << sta.top() << ' ';
sta.push(a[i]);
}
else
{
while(sta.size() && sta.top() >= a[i]) sta.pop();
if(sta.empty())
{
cout << -1 << ' ';
sta.push(a[i]);
}
else
{
cout << sta.top() << ' ';
sta.push(a[i]);
}
}
}
return 0;
}
数组版:
#include <stdio.h>
const int N = 1e5 + 10;
int a[N];
int tt;
int main()
{
int n; scanf("%d", &n);
for(int i = 0; i < n; ++ i)
{
int x;
scanf("%d", &x);
while(tt && a[tt] >= x) tt --;
if(!tt) printf("-1 ");
else printf("%d ", a[tt]);
a[ ++ tt] = x;
}
return 0;
}
三、队列
3.1 滑动窗口
单调队列
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 7;
int a[N], q[N], ff, ee = -1; //q存下标
int main()
{
ios::sync_with_stdio(false); //不能再用C输出
int n, k; cin >> n >> k;
for(int i = 0; i < n; ++ i) cin >> a[i];
//最小值
for(int i = 0; i < n; ++ i)
{
if(i - k + 1 > q[ff]) ++ ff; //左下标出滑窗的界了
while(ff <= ee && a[i] <= a[q[ee]]) -- ee;
q[ ++ ee] = i;
if(i >= k - 1) cout << a[q[ff]] << ' ';
}
//最大值
cout << endl;
ff = 0, ee = -1;
for(int i = 0; i < n; ++ i)
{
if(i - k + 1 > q[ff]) ++ ff;
while(ff <= ee && a[i] >= a[q[ee]]) -- ee;
q[ ++ ee] = i;
if(i >= k - 1) cout << a[q[ff]] << ' ';
}
return 0;
}
四、KMP(待更)
4.1 KMP字符串
五、Trie(未完)
5.1 Trie字符串统计
#include <bits/stdc++.h>
using namespace std;
const int N = 2e4 + 5;
int son[N][26];
int cnt[N];
char str[N], op[2];
int idx;
void insert(char * s)
{
int p = 0;
for(int i = 0; s[i]; ++ i)
{
int u = s[i] - 'a';
if(!son[p][u]) son[p][u] = ++ idx;
p = son[p][u];
}
cnt[p] ++;
}
int count(char *s)
{
int p = 0;
for(int i = 0; s[i]; ++ i)
{
int u = s[i] - 'a';
if(!son[p][u]) return 0;
p = son[p][u];
}
return cnt[p];
}
int main()
{
int T; scanf("%d", &T);
while(T --)
{
scanf("%s%s", op, str);
if(op[0] == 'I') insert(str);
else printf("%d\n", count(str));
}
return 0;
}
5.2 最大异或对
六、并查集(未完)
6.1 合并集合
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;
int p[N];
int find(int b)
{
if(b != p[b]) p[b] = find(p[b]);
return p[b];
}
int main()
{
int n, m; cin >> n >> m;
for(int i = 1; i <= n; ++ i) p[i] = i;
while (m -- )
{
char op; int x, y;
cin >> op >> x >> y;
if(op == 'M') p[find(x)] = find(y);
else
{
if(find(x) == find(y)) puts("Yes");
else puts("No");
}
}
return 0;
}
6.2 连通块中点的数量
加一个数组计数
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;
int p[N];
int cnt[N];
int find(int x)
{
if(x != p[x]) p[x] = find(p[x]);
return p[x];
}
int main()
{
int n, m; cin >> n >> m;
for(int i = 1; i <= n; ++ i)
p[i] = i, cnt[i] = 1;
string op; int a, b;
while (m -- )
{
cin >> op;
if(op == "C")
{
cin >> a >> b;
int aa = find(a), bb = find(b);
//aa 和 bb是两个帮派时合并
if(aa != bb)
{
p[aa] = bb; //bb变成aa的老大
cnt[bb] += cnt[aa];
}
}
else if(op == "Q1")
{
cin >> a >> b;
if(find(a) == find(b)) puts("Yes");
else puts("No");
}
else if(op == "Q2")
{
cin >> a;
cout << cnt[find(a)] << endl;
}
}
return 0;
}
6.3 食物链
七、哈希表
7.1 字符串哈希
- 前缀和
- ULL减消了取模运算
- 将字符串看成进制数
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N = 1e5 + 7, P = 13331;
int n, m;
char str[N];
ULL h[N], p[N]; //h存前缀和
ULL get(int l, int r)
{
return h[r] - h[l - 1] * p[r - l + 1];
}
int main()
{
cin >> n >> m;
scanf("%s", str + 1);
p[0] = 1;
for(int i = 1; i <= n; ++ i)
{
h[i] = h[i-1] * P + str[i];
p[i] = p[i-1] * P;
}
while (m -- )
{
int l1, l2, r1, r2;
cin >> l1 >> r1 >> l2 >> r2;
if(get(l1, r1) == get(l2, r2)) puts("Yes");
else puts("No");
}
return 0;
}
八、堆
8.1 模拟堆
#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
const int N = 1e5 + 7;
int a[N], idx;
int main()
{
int n; cin >> n;
multiset <int> s;
while (n -- )
{
string str; int x; cin >> str;
if(str == "I")
{
cin >> x;
s.insert(x);
a[++ idx] = x;
}
else if(str == "PM")
{
cout << *s.begin() << endl;
}
else if(str == "DM") s.erase(s.find(*s.begin()));
else if(str == "D")
{
cin >> x;
s.erase(s.find(a[x]));
}
else
{
int y;
cin >> x;
s.erase(s.find(a[x]));
cin >> y;
a[x] = y;
s.insert(y);
}
}
return 0;
}