目录
有向图
链式前向星(常用 重点)
这个是倒序存储的,我们一般是倒序输出的,比如这篇
https://mp.csdn.net/mp_blog/creation/editor/119586896
代码+模拟版
/*链式前向星:静态链表实现。添加节点:为了保证O(1)的添加操作,每条边都加在头结点的后面,这就导致本来在头结点后面的节点的前驱结点变为新添加的节点
而新添加的节点为头结点,也就是说正序输入,倒序添加,可以参考gif,用文字叙述如下
例如 V1 ->2,10 ->3,30(这里权值放在终点上,表示边权)的添加过程(暂且忽略权值,仅显示to,next) (^表示NULL,->表示next的地址)
V1 -> 2 ^ ----- V1-> 3 -> ,2 ^ */
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define MAX 1000
#define INF 0x3fffffff //无穷大
using namespace std;
struct node { //静态链表的实现
int to,next,w;//to:边的终点 next:链表中下一节点地址,实际上是同一起点输入的上一条边的地址,因为倒序存储被反转了 w:当前边的权值
} edge[MAX*MAX];
int n,m;
bool vis[MAX];//vis存储的是边!!每个cnt代表一条边!
bool vi[MAX][MAX];
int head[MAX];//表示以i为起点的第一条边存储的位置,实际上你会发现这里的第一条边存储的位置,其实在以i为起点的所有边的最后输入的那个编号,默认为-1
int cnt = 0;//cnt是下标,在静态链表里的地址,每个cnt代表一条边
void addedge(int from,int to,int w) { //为了保证O(1)的添加操作,每条边都加在头结点的后面 正序输入,倒序添加 详见第2行注释
edge[cnt] = {to,head[from],w};//to,next,w next=head[from],也就是说该节点要取代第一条边
printf("cnt=%d from=%d to=%d,next=%d,w=%d,",cnt,from,to,head[from],w);
head[from] = cnt++;//取代
printf("head[%d]=%d\n",from,head[from]);
}
//^ NULL -> -1; 下面为模拟
/*输入
1 2
2 3
3 4
1 3
4 1
1 5
4 5
模拟
edge[0].to = 2; edge[0].next = -1; head[1] = 0;
edge[1].to = 3; edge[1].next = -1; head[2] = 1;
edge[2].to = 4; edge[2],next = -1; head[3] = 2;
edge[3].to = 3; edge[3].next = 0; head[1] = 3;
edge[4].to = 1; edge[4].next = -1; head[4] = 4;
edge[5].to = 5; edge[5].next = 3; head[1] = 5;
edge[6].to = 5; edge[6].next = 4; head[4] = 6;
很明显,head[i]保存的是以i为起点的所有边中编号最大的那个,而把这个当作顶点i的第一条起始边的位置.
这样在遍历时是倒着遍历的,也就是说与输入顺序是相反的,不过这样不影响结果的正确性.
比如以上图为例,以节点1为起点的边有3条,它们的编号分别是0,3,5 而head[1] = 5
我们在遍历以u节点为起始位置的所有边的时候是这样的:
for(int i=head[u];~i;i=edge[i].next) //~1:-1按位取反是0
那么就是说先遍历编号为5的边,也就是head[1],然后就是edge[5].next,也就是编号3的边,然后继续edge[3].next,也
就是编号0的边,可以看出是逆序的. */
void dfs(int now)
{
vis[now] = true;
cout << now <<"\t";
for(int i=head[now];~i;i=edge[i].next)//~1:-1按位取反是0
if(!vis[edge[i].to])
dfs(edge[i].to);
}
void Dfs(int now) {//深搜回路 如果节点有交叉,请同一个起点的输入顺序变为递增,不同起点允许穿插,比如1 2,2 3,3 1,4 5,3 4,5 3
for(int i=head[now]; ~i; i=edge[i].next) { //~1:-1按位取反是0
int to=edge[i].to;
if(!vi[now][to]){
vi[now][to]=1;
printf("%d %d\n",now,to);
Dfs(to);
}
}
}
queue<int> que;
void bfs(int beg) {
que.push(beg);
vis[beg] = true;
while(!que.empty()) {
int top = que.front();
que.pop();
cout<<top<<"\t";
for(int i=head[top]; ~i; i=edge[i].next) {
int to = edge[i].to;
if(!vis[to]) {
que.push(to);
vis[to] = true;
}
}
}
}
int main() {
int x,y,w;
cin>>n>>m;
memset(vis,false,sizeof(vis));
memset(head,-1,sizeof(head));
for(int i=0; i<m; i++) {
cin>>x>>y;
addedge(x,y,1);
}
Dfs(1);
return 0;
}
/*5 5
0 1 1
0 2 1
0 4 1
1 3 1
2 4 1*/
模板
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define MAX 1000
#define INF 0x3fffffff //无穷大
using namespace std;
struct node{//静态链表的实现
int to,next,w;//to:边的终点 next:链表中下一节点地址,实际上是同一起点输入的上一条边的地址,因为倒序存储被反转了 w:当前边的权值
}edge[MAX*MAX];
int n,m;
bool vis[MAX];
int head[MAX];//表示以i为起点的第一条边存储的位置,实际上你会发现这里的第一条边存储的位置,其实在以i为起点的所有边的最后输入的那个编号,默认为-1
int cnt = 0;//cnt是下标,在静态链表里的地址
void addedge(int from,int to,int w)//为了保证O(1)的添加操作,每条边都加在头结点的后面 正序输入,倒序添加 详见第2行注释
{
edge[cnt] = {to,head[from],w};//to,next,w next=head[from],也就是说该节点要取代第一条边
head[from] = cnt++;//取代
}
void dfs(int now)
{
vis[now] = true;
//具体操作栏 cout << now <<"\t";
for(int i=head[now];~i;i=edge[i].next)//~1:-1按位取反是0
if(!vis[edge[i].to])
dfs(edge[i].to);
}
queue<int> que;
void bfs(int beg)
{
que.push(beg);
vis[beg] = true;
while(!que.empty()){
int top = que.front();
que.pop();
//具体操作栏 cout<<top<<"\t";
for(int i=head[top];~i;i=edge[i].next){
int to = edge[i].to;
if(!vis[to]){
que.push(to);
vis[to] = true;
}
}
}
}
int main()
{
return 0;
}
邻接矩阵
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define MAX 1000
#define INF 0x3fffffff //无穷大
using namespace std;
int n,m;
int g[MAX][MAX]; //邻接矩阵
bool vis[MAX];
void dfs(int now)
{
vis[now] = true;
//具体操作栏 cout << now <<"\t";
for(int i=0;i<n;i++){
if(!vis[i] && g[now][i]!=INF){
dfs(i);
}
}
return ;
}
queue<int> que;
void bfs(int beg)
{
que.push(beg);
vis[beg] = true;
while(!que.empty()){
int top = que.front();
que.pop();
//具体操作栏 cout<<top<<"\t";
for(int i=0;i<n;i++){
if(!vis[i] && g[top][i] != INF){
que.push(i);
vis[i] = true;
}
}
}
}
int main()
{
int x,y,w;
cin>>n>>m;
for(int i=0;i<n;i++){//不能用memset
for(int j=0;j<n;j++){
g[i][j] = INF;
}
}
memset(vis,false,sizeof(vis));
for(int i=0;i<m;i++){
cin>>x>>y>>w;
g[x][y] = w;
g[y][x] = w;
}
//dfs(0);
bfs(0);
return 0;
}
/*5 5
0 1 1
0 2 1
0 4 1
1 3 1
2 4 1*/
无向图
邻接表
也可以存储有向图,[x][y]和[y][x]都存储就行,但是一般用链式前向星
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define MAX 1000
#define INF 0x3fffffff //无穷大
using namespace std;
int n,m;
vector<int> g[MAX]; //邻接表
bool vis[MAX];
void dfs(int now)
{
vis[now] = true;
//具体操作栏 cout << now <<"\t";
int len = g[now].size();
int to;
for(int i=0;i<len;i++){
to = g[now][i];
if(!vis[to]){
dfs(to);
}
}
}
queue<int> que;
void bfs(int beg)
{
int len,to;
que.push(beg);
vis[beg] = true;
while(!que.empty()){
int top = que.front();
que.pop();
cout<<top<<"\t";
len = g[top].size();
for(int i=0;i<len;i++){
to = g[top][i];
if(!vis[to]){
dfs(to);
}
}
}
}
int main()
{
int x,y,w;
cin>>n>>m;
memset(vis,false,sizeof(vis));
for(int i=0;i<m;i++){
cin>>x>>y>>w;
g[x].push_back(y);
}
//dfs(0);
bfs(0);
return 0;
}
/*5 5
0 1 1
0 2 1
0 4 1
1 3 1
2 4 1*/