通过学习y总视频中的数据结构部分,学习笔试中常用的 数组 模拟单链表 和 邻接表。
一、数据的存储
1、单链表
#include<bits/stdc++.h>
const int N = 100010;
/*
head表示指向头节点的指针
e[N] 存储每个节点的val
ne[N] 存储每个节点的next指针 对应于e 和 ne 数组中的index
idx表示当前可以从哪个节点开始使用
空节点用idx=-1 表示
换一种方式进行表述:
idx可以理解为"一个链表节点在内存中的地址"。
e[idx]就是获取地址为idx的所对应的val。
ne[idx]就是获取地址为idx所对应节点的下一个节点的地址。
typedef struct ListNode{
int val;
ListNode* next;
};
idx 等价于 ListNode* node = new ListNode()中的node
e[idx] 等价于 node->val;
ne[idx] 等价于 node->next;
*/
int head, e[N], ne[N], idx;
void init(){
// 头节点指向空
head = -1;
// 可从idx为0开始申请新的节点
idx = 0;
}
// 在index为k所对应的节点后面插入一个节点
void add(int k, int x){
e[idx] = x, ne[idx] = ne[k], ne[k] = idx++;
}
void remove(int k){
ne[k] = ne[ne[k]];
}
2、邻接表
邻接表主要用于图的存储(树是一种特殊的无向连通图),相比于单链表,它的头节点转化为了一个数组。
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int h[N], e[N], ne[N], idx++;
// 给序号为a的点 插入一条指向 序号为b的点的 边
int add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
二、图的搜索
图的搜索主要是 深度优先搜索 和 宽度优先搜索,深度优先搜索使用栈,宽度优先搜索使用队列。
1、宽度优先搜索
宽度优先以Acwing中:847. 图中点的层次 这题为例:代码如下所示:
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int h[N], e[N], ne[N], idx;
int d[N];
int n, m;
queue<int> que;
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void bfs(){
// 1.初始化 容易忘记对d数组进行赋值
memset(d, -1, sizeof(d));
d[1] = 0;
que.push(1);
// 只要队列不为空
while(!que.empty()){
// 2.队头出队
int u = que.front();
que.pop();
// 3、尝试添加新元素到队列
for(int i = h[u]; i!=-1; i = ne[i]){
int j = e[i];
if(d[j] == -1){
d[j] = d[u] + 1;
que.push(j);
}
}// end for
}// end while
cout<<d[n]<<endl;
}
int main(){
cin>>n>>m;
// 头节点的初始化 (这个地方很容易忘记)
memset(h, -1, sizeof(h));
for(int i=0; i<m; i++){
int a, b;
cin>>a>>b;
add(a, b);
}// end for
bfs();
}
2、深度优先搜索
关键是使用递归的思路,在进行递归遍历过程中,进行一些其他类似统计数目的一些工作。以Acwing中题为例:846. 树的重心
#include<bits/stdc++.h>
using namespace std;
const int N = 100010, M = 2*N;
int h[N], e[M], ne[M], idx;
bool st[N];
int n;
int ans = INT_MAX;
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
/*
思路就是在进行树或者图的遍历过程之中,
顺便进行一些统计数目的操作
*/
int dfs(int u){
// 1、设置该点被遍历过
st[u] = true;
int sum = 1, res = 0;
for(int i=h[u]; i!=-1; i = ne[i]){
// 获取该点的子节点
int j = e[i];
if(!st[j]){
// 获取该子节点的所有节点数目
int tmp = dfs(j);
sum += tmp;
// 统计哪一个子节点中包含的数目最多
res = max(tmp, res);
}
}// end for
ans = min(ans, max(res, n - sum));
return sum;
}
int main(){
cin>>n;
memset(h, -1, sizeof(h));
for(int i=0; i<n; i++){
int a,b;
cin>>a>>b;
add(a, b), add(b, a);
}// end for
dfs(1);
cout<<ans<<endl;
}
总结一下:
1、理解如何进行图的存储(邻接表)。
2、然后就是背模板。