【数据结构】图的先深搜索、图的先广搜索 (三种方法实现)

目录

7-1 图的先深搜索

输入格式:

输出格式:

输入样例1:

输出鲜例1:

输入样例2:

输出样例1:

7-2 图的先广搜索

输入格式:

输出格式:

输入样例:

输出样例:

 AC代码:

链式前向星存储的邻接表遍历

邻接表存图遍历

 邻接矩阵存图遍历(vector + queue)


7-1 图的先深搜索

输出无向图的给定起点的先深序列。

输入格式:

输入第一行给出三个正整数,分别表示无向图的节点数N(1<N≤10)、边数M(≤50)和探索起始节点编号S(节点从1到N编号)。

随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个节点的编号。

输出格式:

输出从S开始的无向图的先深搜索序列,用一个空格隔开,最后也有一个空格;如果为非连通图,再在结尾处另起一行输出一个0,表示此图非连通。

由于深度优先遍历的节点序列是不唯一的,为了使得输出具有唯一的结果,我们约定以表头插入法构造邻接表。

输入样例1:

6 8 2
1 2
2 3
3 4
4 5
5 6
6 4
3 6
1 5

输出鲜例1:

2 3 6 4 5 1 

输入样例2:

4 3 1
1 2
2 3
3 1

输出样例1:

1 3 2 
0

7-2 图的先广搜索

输出无向图的给定起点的先广序列。

输入格式:

输入第一行给出三个正整数,分别表示无向图的节点数N(1<N≤10)、边数M(≤50)和探索起始节点编号S(节点从1到N编号)。

随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个节点的编号。

输出格式:

输出从S开始的无向图的先广搜索序列,用一个空格隔开,最后也有一个空格;如果为非连通图,再在结尾处另起一行输出一个0,表示此图非连通。

由于广度优先遍历的节点序列是不唯一的,为了使得输出具有唯一的结果,我们约定以表头插入法构造邻接表。

输入样例:

6 8 2
1 2
2 3
3 4
4 5
5 6
6 4
3 6
1 5

输出样例:

2 3 1 6 4 5 

 AC代码:

链式前向星存储的邻接表遍历

/*
* @Author: Spare Lin
* @Project: AcWing2022
* @Date: 2022/7/21 17:22
* @Description: 7-1 图的先深搜索 作者 唐艳琴 单位 中国人民解放军陆军工程大学
* @URL: https://pintia.cn/problem-sets/1456491351779704832/problems/1456491629799145472
*/

#include <iostream>
#include <cstring>

using namespace std;

const int N = 15, M = N * 2;

int h[N], e[M], ne[M], idx;
bool st[N];
int n, m, s, cnt;

void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void dfs(int u) {
    st[u] = true;
    cout << u << ' ';
    cnt++;
    for (int i = h[u]; i != -1; i = ne[i]) { //遍历访问u的子节点
        int j = e[i];
        if (!st[j]) {
            dfs(j);//可以返回搜索的子树大小
        }
    }
}

int main() {
    cin >> n >> m >> s;
    memset(h, -1, sizeof h); //头节点指向-1
    for (int i = 0; i < m; i++) {
        int a, b;
        cin >> a >> b;
        add(a, b), add(b, a);//建立无向图
    }
    dfs(s);
    cout << (cnt != n ? "\n0" : "");
    return 0;
}
/*
* @Author: Spare Lin
* @Project: AcWing2022
* @Date: 2022/7/21 17:25
* @Description: 7-2 图的先广搜索 作者 唐艳琴 单位 中国人民解放军陆军工程大学
* @URL: https://pintia.cn/problem-sets/1456491351779704832/problems/1456491629799145473
*/

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

const int N = 15, M = N * 2;

int h[N], e[M], ne[M], idx;
int n, m, s, cnt;
bool st[N];

void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void bfs(int u) {
    st[u] = true;
    cnt++;
    queue<int> q;
    q.push(u);
    cout << u << ' ';
    while (q.size()) {
        int t = q.front();
        q.pop();
        for (int i = h[t]; i != -1; i = ne[i]) {
            int j = e[i];
            if (!st[j]) {
                st[j] = true;
                cnt++;
                cout << j << ' ';
                q.push(j);
            }
        }
    }
}

int main() {
    cin >> n >> m >> s;
    memset(h, -1, sizeof h); //头节点指向-1
    for (int i = 0; i < m; i++) {
        int a, b;
        cin >> a >> b;
        add(a, b), add(b, a);//建立无向图
    }

    bfs(s);

    cout << (cnt != n ? "\n0" : "");

    return 0;
}

邻接表存图遍历

/*
* @Author: Spare Lin
* @Project: AcWing2022
* @Date: 2022/7/21 17:36
* @Description:  7-1 图的先深搜索 7-2 图的先广搜索
* @URL: https://pintia.cn/problem-sets/1456491351779704832/problems/1456491629799145472
*/

#include <iostream>
#include <cstring>
#include <queue>

using namespace std;

const int MAXV = 15;

typedef struct ANode {        //边结点定义
    int adjvex;               //该边的终点编号
    int weight;               //该边的权值
    struct ANode *nextarc;    //指向下一条边的指针
} ArcNode;//边结点类型

typedef struct Vnode {    //顶点结点定义
    //char data[MAXL];	//顶点其他信息
    int vno;            //改为顶点编号
    ArcNode *firstarc;    //指向第一条边
} VNode;//邻接表头结点类型

typedef VNode AdjList[MAXV];//AdjList是邻接表类型(用来定义结点数组)
typedef struct {
    AdjList adjlist;        //邻接表
    int n, e;                //图中顶点数n和边数e
} ALGraph;//图结构类型

ALGraph *g = (ALGraph *) malloc(sizeof(ALGraph));//图结构

int visited[MAXV];
int cnt; //全局变量:计数器,统计遍历到的顶点总数

//建立无向图的邻接表
void CreateAdj(int n, int e) {
    int i, x, y;
    for (i = 1; i <= n; i++) {
        g->adjlist[i].vno = i;
        g->adjlist[i].firstarc = NULL;
    }
    for (i = 1; i <= e; i++) {
        scanf("%d%d", &x, &y);
        //以x->y的边,创建边结点,并把它添加到顶点x引出的单链表的最前面
        ArcNode *arcnode = (ArcNode *) malloc(sizeof(ArcNode));
        arcnode->adjvex = y;
        arcnode->nextarc = g->adjlist[x].firstarc;
        g->adjlist[x].firstarc = arcnode; //插入作为顶点x的第一条边
        //以y->x的边,创建边结点,并把它添加到顶点x引出的单链表的最前面
        arcnode = (ArcNode *) malloc(sizeof(ArcNode));
        arcnode->adjvex = x;
        arcnode->nextarc = g->adjlist[y].firstarc;
        g->adjlist[y].firstarc = arcnode; //插入作为顶点x的第一条边
    }
    g->n = n;
    g->e = e;
}

//输出图的邻接表
void DispAdj() {
    int i;
    ArcNode *p;
    for (i = 1; i <= g->n; i++) {
        p = g->adjlist[i].firstarc;
        while (p != NULL) {
            printf("→%d", p->adjvex);
            p = p->nextarc;
        }
        printf("→∧\n");
    }
}

//销毁图的邻接表
void DestroyAdj() {
    int i;
    ArcNode *pre, *p;
    for (i = 1; i <= g->n; i++) {
        pre = g->adjlist[i].firstarc;
        while (pre != NULL) {
            p = pre->nextarc;
            free(pre);
            pre = p;
        }
    }
    free(g);
}

void DFS(int v) {//邻接表的DFS算法
    ArcNode *p;            //指向边结点的指针
    printf("%d ", v);    //输出被访问顶点的编号
    visited[v] = 1;        //置已访问标记
    cnt++;                //计数器加1
    p = g->adjlist[v].firstarc;    //p指向顶点v的第一个邻接点
    while (p != NULL) {
        if (visited[p->adjvex] == 0) //若p->adjvex顶点未访问,递归访问它
            DFS(p->adjvex);
        p = p->nextarc;        //p指向顶点v的下一个邻接点
    }
}

void BFS(int v) {           //邻接表的BFS算法
    ArcNode *p;             //指向边结点的指针
    queue<int> qu;          //定义一个队列qu
    int w;                  //定义存放顶点的访问标志的数组
    printf("%d ", v);  //输出被访问顶点的编号
    cnt++;                    //计数器加1
    visited[v] = 1;           //置已访问标记
    qu.push(v);            //v进队
    while (!qu.empty()) {    //队列不空时循环
        w = qu.front();
        qu.pop();            //出队顶点w
        p = g->adjlist[w].firstarc;             //找顶点w的第一个邻接点
        while (p != NULL) {
            if (visited[p->adjvex] == 0) {      //若当前邻接顶点未被访问
                printf("%d ", p->adjvex);//访问相邻顶点
                cnt++;                          //计数器加1
                visited[p->adjvex] = 1;         //置该顶点已被访问的标志
                qu.push(p->adjvex);          //该顶点进队
            }
            p = p->nextarc;    //找顶点w的下一个邻接点
        }
    }
}

int main() {
    int n, e, s;
    while (scanf("%d%d%d", &n, &e, &s)) {
        CreateAdj(n, e);
        //测试输出
//		DispAdj();
        memset(visited, 0, sizeof(visited)); //初始化访问标志
        cnt = 0;
//		DFS(s);
        BFS(s);
        if (cnt < n) {
            printf("\n0");
        }
    }
    //以下是销毁工作,记得去做
    DestroyAdj();
    return 0;
}

 邻接表存图遍历(vector + queue)

/*
* @Author: Spare Lin
* @Project: AcWing2022
* @Date: 2022/7/21 20:35
* @Description: 7-1 图的先深搜索 7-2 图的先广搜索
* @URL: https://pintia.cn/problem-sets/1456491351779704832/problems/1456491629799145472
*/

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

const int N = 15;
vector<int> h[N];
bool st[N];
int n, m, s, cnt;

void dfs(int u) {
    cout << u << ' ';
    st[u] = true;
    cnt++;
    for (auto j : h[u]) {
        if (!st[j]) {
            dfs(j);
        }
    }
}

void bfs(int u) {
    queue<int> q;
    q.push(u);
    while (!q.empty()) {
        int t = q.front();
        q.pop();
        if(!st[t]) {
            st[t] = true;
            cout << t << ' ';
            cnt++;
            for (auto x: h[t]) {
                q.push(x);
            }
        }
    }
}

int main() {
    cin >> n >> m >> s;
    while (m--) {
        int a, b;
        cin >> a >> b;
        h[a].insert(h[a].begin(), b);
        h[b].insert(h[b].begin(), a);//建立无向图
    }
    dfs(s);
    //bfs(s);
    cout << (cnt != n ? "\n0" : "");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值