数据结构--图
2023-12-19 05:33:45
    		? 树具有灵活性,并且存在许多不同的树的应用,但是就树本身而言有一定的局限性,树只能表示层次关系,比如父子关系。而其他的比如兄弟关系只能够间接表示。
推广---? 图
图形结构中,数据元素之间的关系是任意的。
一、图的基本概念



二、图的分类

三、图的相关术语
1、顶点的度
 

无向图:n个顶点找两条,没有方向,



2、路径和路径长度

3.子图
4.图的连通
1)无向图的连通

2)有向图的连通


5.生成树

#不讨论的图:
 
 
四、图的存储方法

1、邻接矩阵存储方法



对称矩阵:
一个对称矩阵是指矩阵的主对角线两侧的元素相等。在这个矩阵中,通过观察可以发现对称性质:矩阵的第i行第j列的元素等于第j行第i列的元素。


**无向图的邻接矩阵建图和度数输出(完整代码)
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#define N (100 + 5)
#define INF 0x3f3f3f3f//定义INF为一个十六进制无穷大常量
typedef char VexType; //顶点为字符类型
typedef int EdgeType;//邻接矩阵类型为整型
typedef struct {
    int n, m; //n个顶点,m条边
    VexType vex[N];//一维数组存放所有顶点的数据信息
    EdgeType edge[N][N];//邻接矩阵(二维数组存放图中所有顶点之间关系的信息)
} adjGraph;
//1.邻接矩阵建图
adjGraph createGraph();
//2.输出图的信息(顶点、邻接矩阵)
void print(adjGraph g);
//3.输出图中每个顶点的度数
void printDegree(adjGraph g);
int main()
{
    //1.建图
    adjGraph g = createGraph();
    //2.输出图的信息
    print(g);
    printDegree(g);
    return 0;
}
adjGraph createGraph()//建图
{
    adjGraph g;
    memset(g.edge, 0, sizeof(g.edge));//内存设置函数--创建图的过程中,所有元素初始化为0
    // g.edge 邻接矩阵
    //sizeof(g.edge) 数组占用的总字节数
    scanf("%d%d", &g.n, &g.m);//输入顶点数和边数
    getchar();//吸收换行符
    //1.输入n个顶点
    for (int i = 0; i < g.n; i++) {
        scanf("%c ", &g.vex[i]);
    }
    //2.输入m条边,按照邻接矩阵存图
    for (int i = 0; i < g.m; i++) {
        char v1, v2;
        scanf("\n%c %c", &v1, &v2);//读入当前边的2个顶点
        int n1 = v1 - 'A', n2 = v2 - 'A';
         //将顶点字符转换为对应的数组索引。
        // 假设顶点标签是大写字母'A'、'B'、'C'等,通过将其减去字符'A'的ASCII码值
        // 可以得到对应的数组索引(0、1、2等)。   
        g.edge[n1][n2] = g.edge[n2][n1] = 1;
        //无向图,邻接矩阵对应的n1行n2列和n2n1列都赋值为1(邻接矩阵的对称性)
        //将对应的邻接矩阵元素设置为1,表示图中对应的顶点之间存在一条边。
    }
    return g;
}
void print(adjGraph g)
{
    printf("图有%d个顶点,%d条边\n", g.n, g.m);
    printf("图的顶点是:");
    for (int i = 0; i < g.n; i++) {
        printf("%c ", g.vex[i]);
    }
    printf("\n图的邻接矩阵是:\n");
    for (int i = 0; i < g.n; i++) {
        for (int j = 0; j < g.n; j++) {
            printf("%4d", g.edge[i][j]);
        }
        printf("\n");
    }
}
void printDegree(adjGraph g)
{
    printf("图中每个顶点的度数是:");
    for (int i = 0; i < g.n; i++) {
        int degree = 0;
        for (int j = 0; j < g.n; j++) {
            if (g.edge[i][j] == 1) {
                degree++;
            }
        }
        printf("%c: %d ", g.vex[i], degree);
    }
    printf("\n");
}
输入样例:

**有向图邻接矩阵建图和度数输出(附完整代码)
修改的部分:
- 将g.edge[n1][n2] = g.edge[n2][n1] = 1; 修改为 g.edge[n1][n2] = 1; 表示从顶点n1指向顶点n2的有向边。
- 把无向图中的度数输出改成入度和出度输出
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#define N (100 + 5)
#define INF 0x3f3f3f3f//定义INF为一个十六进制无穷大常量
typedef char VexType; //顶点为字符类型
typedef int EdgeType;//邻接矩阵类型为整型
typedef struct {
    int n, m; //n个顶点,m条边
    VexType vex[N];//一维数组存放所有顶点的数据信息
    EdgeType edge[N][N];//邻接矩阵(二维数组存放图中所有顶点之间关系的信息)
} adjGraph;
//1.邻接矩阵建图
adjGraph createGraph();
//2.输出图的信息(顶点、邻接矩阵)
void print(adjGraph g);
//3.输出图中每个顶点的度数
void printDegree(adjGraph g);
int main()
{
    //1.建图
    adjGraph g = createGraph();
    //2.输出图的信息
    print(g);
    printDegree(g);
    return 0;
}
adjGraph createGraph()//建图
{
    adjGraph g;
    memset(g.edge, 0, sizeof(g.edge));//内存设置函数--创建图的过程中,所有元素初始化为0
    // g.edge 邻接矩阵
    //sizeof(g.edge) 数组占用的总字节数
    scanf("%d%d", &g.n, &g.m);//输入顶点数和边数
    getchar();//吸收换行符
    //1.输入n个顶点
    for (int i = 0; i < g.n; i++) {
        scanf("%c ", &g.vex[i]);
    }
    //2.输入m条边,按照邻接矩阵存图
    for (int i = 0; i < g.m; i++) {
        char v1, v2;
        scanf("\n%c %c", &v1, &v2);//读入当前边的2个顶点
        int n1 = v1 - 'A', n2 = v2 - 'A';
        //将顶点字符转换为对应的数组索引。
       // 假设顶点标签是大写字母'A'、'B'、'C'等,通过将其减去字符'A'的ASCII码值
       // 可以得到对应的数组索引(0、1、2等)。   
        g.edge[n1][n2] = 1;
        //有向图,邻接矩阵对应的n1行n2列赋值为1
        //将对应的邻接矩阵元素设置为1,表示图中对应的顶点之间存在一条边。
    }
    return g;
}
void print(adjGraph g)
{
    printf("图有%d个顶点,%d条边\n", g.n, g.m);
    printf("图的顶点是:");
    for (int i = 0; i < g.n; i++) {
        printf("%c ", g.vex[i]);
    }
    printf("\n图的邻接矩阵是:\n");
    for (int i = 0; i < g.n; i++) {
        for (int j = 0; j < g.n; j++) {
            printf("%4d", g.edge[i][j]);
        }
        printf("\n");
    }
}
void printDegree(adjGraph g)
{
    printf("图中每个顶点的入度是:\n");
    for (int i = 0; i < g.n; i++) {
        int indegree = 0;
            for (int j = 0; j < g.n; j++) {
                if (g.edge[j][i] == 1) {
                    indegree++;
                 }
            }
            printf("%c: %d \n", g.vex[i], indegree);
       }
       
  
    printf("图中每个顶点的出度是:\n");
    for (int i = 0; i < g.n; i++) {
        int outdegree = 0;
        for (int j = 0; j < g.n; j++) {
            if (g.edge[i][j] == 1) {
                outdegree++;
            }
        }
        printf("%c: %d \n", g.vex[i], outdegree);
        
    }
}
测试样例:


**有向带权图邻接矩阵建图和度数输出(含完整代码)


#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#define N (100 + 5)
#define INF 0x3f3f3f3f//定义INF为一个十六进制无穷大常量
typedef char VexType; //顶点为字符类型
typedef int EdgeType;//邻接矩阵类型为整型
typedef struct {
    int n, m; //n个顶点,m条边
    VexType vex[N];//一维数组存放所有顶点的数据信息
    EdgeType edge[N][N];//邻接矩阵(二维数组存放图中所有顶点之间关系的信息)
} adjGraph;
//1.邻接矩阵建图
adjGraph createGraph();
//2.输出图的信息(顶点、邻接矩阵)
void print(adjGraph g);
//3.输出图中每个顶点的度数
void printDegree(adjGraph g);
int main()
{
    //1.建图
    adjGraph g = createGraph();
    //2.输出图的信息
    print(g);
    printDegree(g);
    return 0;
}
adjGraph createGraph()//建图
{
    adjGraph g;
    memset(g.edge, 0, sizeof(g.edge));//内存设置函数--创建图的过程中,所有元素初始化为0
    // g.edge 邻接矩阵
    //sizeof(g.edge) 数组占用的总字节数
    scanf("%d%d", &g.n, &g.m);//输入顶点数和边数
    getchar();//吸收换行符
    //1.输入n个顶点
    for (int i = 0; i < g.n; i++) {
        scanf("%c ", &g.vex[i]);
    }
    //2.输入m条边,按照邻接矩阵存图 
    // 将邻接矩阵初始化为INF
    for (int i = 0; i < g.m; i++) {
        for (int j = 0; j < g.m; j++) {
            g.edge[i][j] = INF;
        }
    }
    for (int i = 0; i < g.m; i++) {
        char v1, v2;
        int weight;
        scanf("\n%c %d %c", &v1, &weight, &v2);//读入当前边的2个顶点
        int n1 = v1 - 'A', n2 = v2 - 'A';
        //将顶点字符转换为对应的数组索引。
        // 假设顶点标签是大写字母'A'、'B'、'C'等,通过将其减去字符'A'的ASCII码值
        // 可以得到对应的数组索引(0、1、2等)。
       
        if (n1 == n2) {
            g.edge[n1][n2] = 0;
        }
        else {
            g.edge[n1][n2] = weight;
            g.edge[n2][n1] = INF; // 反方向的边权值设置为INF
        }
    }
    return g;
}
void print(adjGraph g)
{
    printf("图有%d个顶点,%d条边\n", g.n, g.m);
    printf("图的顶点是:");
    for (int i = 0; i < g.n; i++) {
        printf("%c ", g.vex[i]);
    }
    printf("\n图的邻接矩阵是:\n");
    for (int i = 0; i < g.n; i++) {
        for (int j = 0; j < g.n; j++) {
            if (i == j) printf("0 ");
            else if (g.edge[i][j] == INF)
            {
                printf("INF ");
           }
            else  {
                   printf("%-4d", g.edge[i][j]);
            }
                  
        
            
        }
        printf("\n");
    }
}
void printDegree(adjGraph g)
{
    printf("图中每个顶点的入度是:\n");
    for (int i = 0; i < g.n; i++) {
        int indegree = 0;
        for (int j = 0; j < g.n; j++) {
     
                  if (g.edge[j][i] != 0 && g.edge[j][i] != INF) {
                     indegree++;
                 }
    
            
        }
        printf("%c: %d \n", g.vex[i], indegree);
    }
    printf("图中每个顶点的出度是:\n");
    for (int i = 0; i < g.n; i++) {
        int outdegree = 0;
        for (int j = 0; j < g.n; j++) {
                if (g.edge[i][j] != 0&& g.edge[i][j] != INF) {
                    outdegree++;
                }
            }
        
        printf("%c: %d \n", g.vex[i], outdegree);
    }
}
样例:

2、邻接表存储方法
? 对每一个顶点建立一个单链表,将同一个顶点发出的边链接在一个称为边链表的单链表中。

头插法:


五、图的遍历


六、最小生成树

? ? ??
七、最短路径问题

八、AOV网与拓扑排序
九、AOE网与关键路径
    			文章来源:https://blog.csdn.net/NNLYF_/article/details/134793551
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
    	本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!


