声明:

#include <bits/stdc++.h>
using namespace std;
#define OVERFLOW -2 //内存溢出错误常量
#define OK 1 //表示操作正确的常量
#define ERROR 0 //表示操作错误的常量
#define TRUE 1 //表示逻辑真的常量
#define FALSE 0 //表示逻辑假的常量

typedef int Status; //指定状态码的类型是int
#define INFINITY 65535
#define MAX_VERTEX_NUM 20

typedef enum{
   
  //(有向图=0,有向网=1,无向图=2,无向网=3)
    DG,
    DN,
    UDG,
    UDN
} GraphKind;
typedef int VRType;
typedef int VertexType;
typedef struct ArcCell{
   
    VRType adj;
} ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

typedef struct{
   
    VertexType vexs[MAX_VERTEX_NUM];
    AdjMatrix arcs;
    int vexnum, arcnum;
    GraphKind kind;
} MGraph;

广度优先搜索需使用队列:

//----------队列---------------------------------
#define MAXQSIZE 100 //队列的最大长度
typedef int Status;
typedef int QElemType;

typedef struct{
    //循环队列的C语言描述
    QElemType *base; //初始化动态分配存储空间
    int front;       //头指针,若队列不空,指向队头元素
    int rear;        //尾指针,若队列不空,指向队尾元素的下一个位置
} SqQueue;

//----------------------循环队列的主要操作------------------------
Status InitQueue_Sq(SqQueue &Q){
   
    if (!(Q.base = (QElemType *)malloc(MAXQSIZE * sizeof(QElemType)))){
   
        printf("内存分配失败,程序即将退出!\n");
        exit(OVERFLOW);
    }
    Q.front = Q.rear = 0;
    return OK;
}
Status DestoryQueue_Sq(SqQueue &Q){
   
    if (Q.base){
   
        free(Q.base);
    }
    Q.base = NULL;
    Q.front = Q.rear = 0;
    return OK;
}
Status QueueEmpty_Sq(SqQueue Q){
   
    if (Q.rear == Q.front){
   
        return TRUE;
    }
    else{
   
        return FALSE;
    }
}
Status EnQueue_Sq(SqQueue &Q, QElemType e){
   
    if ((Q.rear + 1) % MAXQSIZE == Q.front){
    
        return ERROR;
    } 
    Q.base[Q.rear] = e;
    Q.rear = (Q.rear + 1) % MAXQSIZE;
    return OK;
} 
Status DeQueue_Sq(SqQueue &Q, QElemType &e){
   
    if (QueueEmpty_Sq(Q)){
   
        return ERROR;
    }
    e = Q.base[Q.front];
    Q.front = (Q.front + 1) % MAXQSIZE;
    return OK;
}

基于邻接矩阵的图上操作:

int LocateVex(MGraph G, VertexType u) {
   
    int i;
    
    for(i = 0; i < G.vexnum; i++) {
   
        if(G.vexs[i] == u) {
   
            return i;
        }
    }
    
    return -1;
}

//算法7.2
Status CreateUDN(MGraph &G){
   
    VertexType v1, v2;
    int w, i, j;
    printf("请依次输入无向网G的顶点数和弧数\n");
    scanf("%d%d", &G.vexnum, &G.arcnum);
    printf("请依次输入无向网G的顶点名称,用空格隔开\n");
    for (int i = 0; i < G.vexnum; ++i){
   
        scanf("%d", &G.vexs[i]);
    }
    for (int i = 0; i < G.vexnum; ++i)
        for (int j = 0; j < G.vexnum; ++j)
            G.arcs[i][j].adj = INFINITY;
    printf("请依次输入无向网G每条弧依附的两顶点名称及权值,输完一组按回车\n");
    for (int k = 0; k < G.arcnum; ++k)
    {
   
        scanf("%d", &v1);
        scanf("%d", &v2);
        scanf("%d", &w);
        i = LocateVex(G, v1);
        j = LocateVex(G, v2);
        G.arcs[i][j].adj = w;
        G.arcs[j][i] = G.arcs[i][j];
    } 
    return OK;
} // CreateUDN
Status CreateUDG(MGraph &G){
   
    VertexType v1, v2;
    int i, j;
    printf("请依次输入无向图G的顶点数和弧数\n");
    scanf("%d%d", &G.vexnum, &G.arcnum);
    printf("请依次输入无向图G的顶点名称,用空格隔开\n");
    for (int i = 0; i < G.vexnum; ++i){
   
        scanf("%d", &G.vexs[i]);
    }
    for (int i = 0; i < G.vexnum; ++i)
        for (int j = 0; j < G.vexnum; ++j)
            G.arcs[i][j].adj = 0;
    printf("请依次输入无向图G每条弧依附的两顶点名称,输完一组按回车\n");
    for (int k = 0; k < G.arcnum; ++k){
   
        scanf("%d", &v1);
        scanf("%d", &v2);
        i = LocateVex(G, v1);
        j = LocateVex(G, v2);
        G.arcs[i][j].adj = 1;
        G.arcs[j][i] = G.arcs[i][j];
    }
    return OK;
}

Status CreateDN(MGraph &G)
{
   
    VertexType v1, v2;
    int w, i, j;
    printf("请依次输入有向网G的顶点数和弧数\n");
    scanf("%d%d", &G.vexnum, &G.arcnum);
    printf("请依次输入有向网G的顶点名称,用空格隔开\n");
    for (int i = 0; i < G.vexnum; ++i){
   
        scanf("%d", &G.vexs[i]);
    }
    for (int i = 0; i < G.vexnum; ++i)
        for (int j = 0; j < G.vexnum; ++j)
            G.arcs[i][j].adj = INFINITY;
    printf("请依次输入有向网G每条弧依附的两顶点名称及权值,输完一组按回车\n");
    for (int k = 0; k < G.arcnum; ++k){
   
        scanf("%d", &v1);
        scanf("%d", &v2);
        scanf("%d", &w);
        i = LocateVex(G, v1);
        j = LocateVex(G, v2);
        G.arcs[i][j].adj = w;
    } 
    return OK;
} // CreateDN

Status CreateDG(MGraph &G){
   
    VertexType v1, v2;
    int i, j;
    printf("请依次输入有向图G的顶点数和弧数\n");
    scanf("%d%d", &G.vexnum, &G.arcnum);
    printf("请依次输入有向图G的顶点名称,用空格隔开\n");
    for (int i = 0; i < G.vexnum; ++i){
   
        scanf("%d", &G.vexs[i]);
    }
    for (int i = 0; i < G.vexnum; ++i)
        for (int j = 0; j < G.vexnum; ++j)
            G.arcs[i][j].adj = 0;
    printf("请依次输入有向图G每条弧依附的两顶点名称,输完一组按回车\n");
    for (int k = 0; k < G.arcnum; ++k){
   
        scanf("%d", &v1);
        scanf("%d", &v2);
        i = LocateVex(G, v1);
        j = LocateVex(G, v2);
        G.arcs[i][j].adj = 1;
    }
    return OK;
} // CreateDG

//算法7.1
Status CreateGraph(MGraph &G){
   
    printf("请输入您想构造的图的类型:有向图输入0,有向网输入1,无向图输入2,无向网输入3):");
    scanf("%d", &G.kind);
    switch (G.kind)
    {
   
    case DG:
        return CreateDG(G); //构造有向图G
    case DN:
        return CreateDN(G); //构造有向网G
    case UDG:
        return CreateUDG(G); //构造无向图G
    case UDN:
        return CreateUDN(G); //构造无向网G
    default:
        return ERROR;
    } 
} //CreateGraph

Status DestroyGraph(MGraph &G){
   
    if (G.kind % 2){
   
        for (int i = 0; i < G.vexnum; i++){
   
            for (int j = 0; j < G.vexnum; j++){
   
                G.arcs[i][j].adj = INFINITY;
            } 
        }    
    }  
    else{
    //若是图
        for (int i = 0; i < G.vexnum; i++){
   
            for (int j = 0; j < G.vexnum; j++){
   
                G.arcs[i][j].adj = 0;
            } 
        }     
    }   
    G.vexnum = 0;
    G.arcnum = 0;
} //DestroyGraph
Status PrintAdjMatrix(MGraph G){
   
    printf(" ");
    for (int i = 0; i < G.vexnum; i++){
   
        printf(" %3d ", G.vexs[i]);
    }
    printf("\n");
    printf(" +");
    for (int i = 0; i < G.vexnum; i++){
   
        printf("-----");
    } 
    printf("\n");
    for (int i = 0; i < G.vexnum; i++){
   
        printf(" %3d |", G.vexs[i]);
        for (int j = 0; j < G.vexnum; j++){
   
            if (G.arcs[i][j].adj == INFINITY){
   
                printf(" ∞ ");
            } 
            else{
   
                printf(" %3d ", G.arcs[i][j].adj);
            }
        }
        printf("\n |\n");
    }
} //PrintAdjMatrix
VertexType &GetVex(MGraph G, int v){
   
    if (v >= G.vexnum || v < 0){
   
        exit(ERROR);
    }
    return G.vexs[v];
} //GetVex
Status PutVex(MGraph &G, VertexType v, VertexType value){
   
    int k = LocateVex(G, v);
    if (k < 0){
   
        return ERROR;
    }
    G.vexs[k] = value;
    return OK;
} //PutVex

int FirstAdjVex(MGraph G, VertexType v) {
   
    int kv,j;
    VRType adj;
    kv = LocateVex(G, v);
    if(kv == -1)
        return -1;  
    if(G.kind == DG || G.kind == UDG) {
   
        adj = 0;            // 图
    } else if(G.kind == DN || G.kind == UDN) {
   
        adj = INFINITY;     // 网
    } else {
   
        return -1;
    }
    for(j = 0; j < G.vexnum; j++) {
   
        if(G.arcs[kv][j].adj != adj) {
   
            return j;
        }
    }
    return -1;
}
int NextAdjVex(MGraph G, VertexType v, VertexType w) {
   
    int kv, kw, j;
    VRType adj;
    kv = LocateVex(G, v);
    if(kv == -1) 
        return -1; 
    kw = LocateVex(G, w);
    if(kw == -1) {
   
        return -1;  
    }
    if(G.kind == DG || G.kind == UDG) {
   
        adj = 0;        // 图
    } else if(G.kind == DN || G.kind == UDN) {
   
        adj = INFINITY; // 网
    } else {
   
        return -1;
    }
    for(j = kw + 1; j < G.vexnum; j++) {
   
        if(G.arcs[kv][j].adj != adj) {
   
            return j;
        }
    }
    return -1;
}
Status InsertVex(MGraph &G, VertexType v){
   
    int j = 0;
    if (G.kind % 2){
   
        j = INFINITY;
    }
    G.vexs[G.vexnum] = v;
    for (int i = 0; i <= G.vexnum; i++){
   
        G.arcs[G.vexnum][i].adj = G.arcs[i][G.vexnum].adj = j;
    }
    G.vexnum++;
    return OK;
} //InsertVex
Status DeleteVex(MGraph &G, VertexType v){
   
    VRType m = 0;
    if (G.kind % 2){
   
        m = INFINITY;
    } 
    int k = LocateVex(G, v);
    if (k < 0){
    
        return ERROR;
    } 
    for (int j = 0; j < G.vexnum; j++){
   
        if (G.arcs[j][k].adj != m){
   
            G.arcs[j][k].adj = m;
            G.arcnum--;
        }
        if (G.arcs[k][j].adj != m) {
   
            G.arcs[k][j].adj = m;
            G.arcnum--;
        } 
    }   
    for (int j = k + 1; j < G.vexnum; j++){
   
        G.vexs[j - 1] = G.vexs[j];
    } 
    for (int i = 0; i < G.vexnum; i++){
   
        for (int j = k + 1; j < G.vexnum; j++){
   
            G.arcs[i][j - 1] = G.arcs[i][j];
        } 
    }     
    for (int i = 0; i < G.vexnum; i++){
   
        for (int j = k + 1; j < G.vexnum; j++){
   
            G.arcs[j - 1][i] = G.arcs[j][i];
        } 
    }
    G.vexnum--;
    return OK;
} //DeleteVex
Status InsertArc(MGraph &G, VertexType v, VertexType w){
   
    int v1 = LocateVex(G, v);
    int w1 = LocateVex(G, w);
    if (v1 < 0 || w1 < 0){
   
        return ERROR;
    }
    G.arcnum++;
    if (G.kind % 2){
   
        printf("请输入此弧或边的权值: ");
        scanf("%d", &G.arcs[v1][w1].adj);
    }
    else
        G.arcs[v1][w1].adj = 1;
    if (G.kind > 1)
        G.arcs[w1][v1].adj = G.arcs[v1][w1].adj;
    return OK;
} //InsertArc

Status DeleteArc(MGraph &G, VertexType v, VertexType w){
   
    int j = 0;
    if (G.kind % 2){
   
        j = INFINITY;
    }
    int v1 = LocateVex(G, v);
    int w1 = LocateVex(G, w);
    if (v1 < 0 || w1 < 0)
        return ERROR;
    G.arcs[v1][w1].adj = j;
    if (G.kind >= 2)
        G.arcs[w1][v1].adj = j;
    G.arcnum--;
    return OK;
} //DeleteArc

DFS:

深度优先搜索属于图算法的一种,是一个针对图和树的遍历算法,英文缩写为DFS即Depth First Search。深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题等等。一般用堆数据结构来辅助实现DFS算法。其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。

//-----------------------深度优先遍历DFS-----------------------------
int visited[MAX_VERTEX_NUM];
Status (*VisitFunc)(int v);
Status Print(int v){
   
    printf(" %3d ", v);
    return OK;
}
//算法7.5
void DFS(MGraph G, int v){
   
    visited[v] = TRUE;
    VisitFunc(G.vexs[v]);
    for (int w = FirstAdjVex(G, G.vexs[v]); w >= 0;w = NextAdjVex(G, G.vexs[v], G.vexs[w])){
   
        if (!visited[w]){
   
            DFS(G, w);
        } 
    } 
} //DFS
//算法7.4
void DFSTraverse(MGraph G, Status (*Visit)(int v)){
   
    VisitFunc = Visit;
    for (int v = 0; v < G.vexnum; ++v)
        visited[v] = FALSE;
    for (int v = 0; v < G.vexnum; ++v){
   
        if (!visited[v])
            DFS(G, v);
    }
} //DFSTraverse

BFS:

广度优先搜索(也称宽度优先搜索,缩写BFS,以下采用广度来描述)是连通图的一种遍历算法这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。基本过程,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。一般用队列数据结构来辅助实现BFS算法。

//----------------广度优先遍历 (需要使用队列)BFS------------
//算法7.6
void BFSTraverse(MGraph G, Status (*Visit)(int v)){
   
    int u;
    SqQueue Q;
    for (int v = 0; v < G.vexnum; ++v){
   
        visited[v] = FALSE;
    }
    InitQueue_Sq(Q);
    for (int v = 0; v < G.vexnum; ++v){
   
        if (visited[v])
            continue;
        visited[v] = TRUE;
        Visit(G.vexs[v]);
        EnQueue_Sq(Q, v);
        while (!QueueEmpty_Sq(Q)){
   
            DeQueue_Sq(Q, u);
            for (int w = FirstAdjVex(G, G.vexs[u]); w >= 0;
                    w = NextAdjVex(G, G.vexs[u], G.vexs[w])){
   
                if (!visited[w]){
   
                    visited[w] = TRUE;
                    Visit(G.vexs[w]);
                    EnQueue_Sq(Q, w);
                } 
            }    
        }        
    }
} //BFSTraverse

测试函数:

//----------------------主函数----------------------
int main(){
   

    printf("\n-------------图的邻接矩阵表示法基本操作测试程序--------------\n\n");
    MGraph G;
    VertexType v1, v2;
    int n;
    printf("->测试图的创建:\n");
    CreateGraph(G);
    // printf("\n->创建成功后图的邻接矩阵:\n\n");
    // PrintAdjMatrix(G);
    //测试图的遍历(深度、广度)
    printf("\n->测试图的遍历:\n");
    printf("->深度优先遍历结果:");
    DFSTraverse(G, Print);

    printf("\n->广度优先遍历结果:");
    BFSTraverse(G, Print);
    printf("\n");
    return 0;
}

输入样例:

请输入您想构造的图的类型:有向图输入0,有向网输入1,无向图输入2,无向网输入3):2
请依次输入无向图G的顶点数和弧数
8 9
请依次输入无向图G的顶点名称,用空格隔开
1 2 3 4 5 6 7 8
请依次输入无向图G每条弧依附的两顶点名称,输完一组按回车
1 2
1 3
2 4
2 5
4 8
5 8
3 6
3 7
6 7

输出样例:

->测试图的遍历:
->深度优先遍历结果:   1    2    4    8    5    3    6    7
->广度优先遍历结果:   1    2    3    4    5    6    7    8 

更多数据结构代码实现请关注我的专栏数据结构

或者进入2021-10-16【严蔚敏数据结构代码实现合集】【c语言学习必备】学习