第二讲 数据结构
1.单链表
AcWing 826. 单链表
https://www.acwing.com/problem/content/description/828/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int e[N],ne[N],head = -1,idx;
//向链表头插入一个数x O(1)
void add_to_head(int x){ //最后一个元素指向-1
e[idx] = x;
ne[idx] = head;
head = idx;
idx++;
}
//在第k个插入的数后面插入一个数x O(1),要用链表那就是O(n)
void add(int k,int x){
k--; //idx是从0开始的
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx;
idx++;
}
// 删除第 k 个插入的数后面的数(当 k 为 0 时,表示删除头结点)O(1)
void del(int k){
if(k == 0) head = ne[head];
else{
ne[k-1] = ne[ne[k-1]];
}
}
int main(){
int M; cin >> M; //M次操作
while(M--){
char op; cin >> op;
int k,x;
if(op == 'H'){ //H x,表示向链表头插入一个数 x
cin >> x;
add_to_head(x);
}else if(op == 'I'){ // I k x,表示在第 k 个插入的数后面插入一个数 x,此操作中 k 均大于 0
cin >> k >> x;
add(k,x);
}else if(op == 'D'){ // 表示删除第 k 个插入的数后面的数(当 k 为 0 时,表示删除头结点)
cin >> k;
del(k);
}
}
for(int i = head; i != -1; i = ne[i]){
cout << e[i] << " ";
}
return 0;
}
2. 双链表
AcWing 827. 双链表
https://www.acwing.com/problem/content/829/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int e[N],l[N],r[N],head = - 1,idx;
//在节点a(下标idx)的右边插入一个数
void insert(int a,int x){
e[idx] = x;
l[idx] = a, r[idx] = r[a];
l[r[a]] = idx,r[a] = idx;
idx++;
}
//删除节点a
void remove(int a){
l[r[a]] = l[a];
r[l[a]] = r[a];
}
int main(){
int M; cin >> M; //M次操作
// 0是左端点,1是右端点
l[0] = -1, r[1] = -1;
r[0] = 1, l[1] = 0;
idx = 2;
while(M--){
string op; cin >> op;
int k,x;
if(op == "L"){ //在链表的最左端插入数 x
cin >> x;
insert(0,x);
}else if(op == "R"){ // 在链表的最右端插入数 x
cin >> x;
insert(l[1],x);
}else if(op == "D"){ // 表示将第 k 个插入的数删除
cin >> k;
remove(k+1);
}else if(op == "IL"){ // IL k x,表示在第 k 个插入的数左侧插入一个数
cin >> k >> x;
insert(l[k+1],x);
}else if(op == "IR"){ // 在第 k 个插入的数右侧插入一个数
cin >> k >> x;
insert(k+1,x);
}
}
for(int i = r[0]; i != 1; i = r[i]){
cout << e[i] << " ";
}
return 0;
}
3.栈
AcWing 828. 模拟栈
https://www.acwing.com/problem/content/830/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int stk[N],idx = -1;
int main(){
int m; cin >> m;
while(m--){
string op;
cin >> op;
int x;
if(op == "push"){
cin >> x;
stk[++idx] = x;
}
if(op == "pop"){
idx--;
}
if(op == "query"){ // 查询栈顶元素
cout << stk[idx] << endl;
}
if(op == "empty"){
if(idx == -1) cout << "YES" << endl;
else cout << "NO" << endl;
}
}
return 0;
}
AcWing 3302. 表达式求值☆
https://www.acwing.com/problem/content/3305/
点击查看代码
4.队列
AcWing 829. 模拟队列
https://www.acwing.com/problem/content/831/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int q[N],hh,tt = -1;
int main(){
int M; cin >> M; while(M--){
string op; cin >> op;
int x;
if(op == "push"){ //从队尾插入一个数
cin >> x;
q[++tt] = x;
}
if(op == "pop"){ //从队头弹出一个数
hh++;
}
if(op == "empty"){
if(tt >= hh){
cout << "NO" << endl;
}else{
cout << "YES" << endl;
}
}
if(op == "query"){ //查询队头元素
cout << q[hh] << endl;
}
}
return 0;
}
5.单调栈
AcWing 830. 单调栈
https://www.acwing.com/problem/content/832/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int stk[N],tt = -1;
int n;
int main(){
cin >> n;
for(int i = 1; i <= n; i++){
int x; cin >> x;
while(tt >= 0 && stk[tt] >= x) tt--;
if(tt >= 0) cout << stk[tt] << " ";
else cout << -1 << " ";
stk[++tt] = x;
}
return 0;
}
6. 单调队列
AcWing 154. 滑动窗口
https://www.acwing.com/problem/content/156/
点击查看代码
#include <iostream>
using namespace std;
const int N = 1000010;
int a[N];
int q[N],hh, tt = -1;
int main(){
int n,k; cin >> n >> k;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++){
if(tt >= 0 && q[hh] < i-k+1) hh++; //判断窗口头是否包含在内
while(tt >= hh && a[q[tt]] > a[i]) tt--; //单调递增队列
q[++tt] = i;
if(i-k >= 0) cout << a[q[hh]] << " ";
}
cout << endl;
//同样的道理
hh = 0, tt = -1;
for(int i = 1; i <= n; i++){
if(tt >= 0 && q[hh] < i-k+1) hh++;
while(tt >= hh && a[q[tt]] < a[i]) tt--;
q[++tt] = i;
if(i-k >= 0) cout << a[q[hh]] << " ";
}
return 0;
}
7.KMP ⭐️⭐️⭐️⭐️⭐️
AcWing 831. KMP字符串
https://www.acwing.com/problem/content/833/
点击查看代码
8.trie字典树
AcWing 835. Trie字符串统计
https://www.acwing.com/problem/content/description/837/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int son[N][26],cnt[N],idx;
void insert(string s){
int p = 0; //从根节点开始向下插入
for(int i = 0; i < s.length(); i++){
int t = s[i] - 'a';
if(son[p][t] == 0) son[p][t] = ++idx; //没有这个节点就创建这个节点,该节点的值为++idx,也是孩子节点的下标
p = son[p][t];
}
cnt[p]++;
}
int query(string s){
int p = 0;
for(int i = 0; i < s.length(); i++){
int t = s[i] - 'a';
if(son[p][t] == 0) return 0;
p = son[p][t];
}
return cnt[p];
}
int main(){
int N; cin >> N; while(N--){
string op; cin >> op;
string x;
if(op == "I"){
cin >> x;
insert(x);
}
if(op == "Q"){
cin >> x;
cout << query(x) << endl;
}
}
return 0;
}
9.并查集
AcWing 836. 合并集合
https://www.acwing.com/problem/content/838/
点击查看代码
#include <iostream>
using namespace std;
const int N = 100010;
int fa[N];
int n,m;
int get(int x){
if(x == fa[x]) return x;
return fa[x] = get(fa[x]);
}
void merge(int a,int b){
fa[get(a)] = get(b);
}
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++) fa[i] = i;
while(m--){
char op; cin >> op;
int a,b;
if(op == 'M'){
cin >> a >> b;
merge(a,b);
}else{
cin >> a >> b;
if(get(a) == get(b)) cout << "Yes" << endl;
else cout << "No" << endl;
}
}
return 0;
}
10堆
AcWing 838. 堆排序
https://www.acwing.com/activity/content/problem/content/888/
点击查看代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int h[N],si; // 堆的一维数组,si表示h的最后一个下标size
int m,n;
void down(int u){
int t = u; // t存放当前节点、左孩子、右孩子三者的最小节点下标
if(u * 2 <= si && h[u*2] < h[t]) t = u*2; // 左孩子比u节点小
if(u * 2 + 1 <= si && h[u*2 + 1] < h[t]) t = u*2 + 1;
if(t != u){
swap(h[t],h[u]);
down(t);
}
}
int main(){
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> m; // n个整数,输出前m个数
for(int i = 1; i <= n; i++) cin >> h[i];
si = n;
for(int i = n/2; i >= 1; i--) down(i); //建堆
while(m--){
cout << h[1] << " ";
h[1] = h[si]; // 最后一节点覆盖一个节点,down(1);
si--;
down(1);
}
return 0;
}
11.哈希表(图的表示方法)
AcWing 840. 模拟散列表
https://www.acwing.com/problem/content/description/842/
点击查看代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010;
int h[N],e[N],ne[N],idx;
void insert(int x){
int k = (x%N + N) % N;
e[idx] = x;
ne[idx] = h[k];
h[k] = idx++;
}
bool find(int x){
int k = (x % N + N) % N;
for(int i = h[k]; i != -1; i = ne[i]){
if(e[i] == x) return true;
}
return false;
}
int main(){
int n; cin >> n;
memset(h,-1,sizeof(h));
while(n--){
char op; cin >> op;
int x;
if(op == 'I'){
cin >> x;
insert(x);
}else{
cin >> x;
if(find(x)) cout << "Yes" << endl;
else cout << "No" << endl;
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律