数据结构(四)


图是网络型的非线性结构,图中的所有节点之间是多对多的关系
图(Graph)——图G是由两个集合V(G)和E(G)组成的,记为G=(V,E)
其中:V(G)是顶点的非空有限集
           E(G)是边的有限集合,边是顶点的无序对或有序对
有向图——有向图G是由两个集合V(G)和E(G)组成的
 其中:V(G)是顶点的非空有限集
           E(G)是有向边(也称弧)的有限集合,弧是顶点的有序对,记为<v,w>,v,w是顶点,v为弧尾,w为弧头
无向图——无向图G是由两个集合V(G)和E(G)组成的
 其中:V(G)是顶点的非空有限集
           E(G)是边的有限集合,边是顶点的无序对,记为(v,w)或(w,v),并且(v,w)=(w,v)

有向完备图——n个顶点的有向图最大边数是n(n-1)
无向完备图——n个顶点的无向图最大边数是n(n-1)/2
权——与图的边或弧相关的数叫~
网——带权的图叫~
子图——如果图G(V,E)和图G‘(V’,E‘),满足:
V’包含于V
E’包含于E
  则称G‘为G的子图
顶点的度
无向图中,顶点的度为与每个顶点相连的边数
有向图中,顶点的度分成入度与出度
入度:以该顶点为头的弧的数目
出度:以该顶点为尾的弧的数目

图的表示
有两种主要的方法:邻接列表和邻接矩阵。
图的存储:
a. 多重链表
b. 邻接矩阵:
在邻接矩阵实现中,由行和列都表示顶点,由两个顶点所决定的矩阵对应元素表示这里两个顶点是否相连、如果相连这个值表示的是相连边的权重。
//图的邻接矩阵存储方式的表示:
//图的类型
enum Graphikind {DG, DN, UDG, UDN}; //(有向图、有向网,无向图、无向网)
//图的定义
typedef struct Node
{
    int *vex;  //顶点的一维数组
    int vexnum; //顶点的个数
    int edge; //顶点的边数
    int **adjMartrix; //邻接矩阵
    enum Graphikind kind;  //图的类型
}Node;
特点:
无向图的邻接矩阵对称,可压缩存储;有n个顶点的无向图需存储空间为n(n+1)/2
有向图邻接矩阵不一定对称;有n个顶点的有向图需存储空间为n2
无向图中顶点Vi的度TD(Vi)是邻接矩阵A中第i行元素之和
有向图中,
顶点Vi的出度是A中第i行元素之和
顶点Vi的入度是A中第i列元素之和

c. 关联矩阵

d. 邻接表: 将每一个顶点相关的边组织成一个链表
//图的邻接表存储方式的表示
typedef char vertextype; 
//表节点结构
typedef struct ArcNode
{
    int adjvex; //某条边指向的那个顶点的位置(一般是数组的下标)
    struct ArcNode *nextarc; //指向下一个表结点的指针
    int weight; //如果是边带权的网,weight表示边的权
}ArcNode;

//头节点结构
typedef struct Vnode
{
    vertextype data; //记录每一个顶点的信息(一般就是给顶点的标记)
    ArcNode *fristarc; //指向第一条依附在该顶点上的边的信息(指向和该顶点相关的边的链表的第一个节点)
}Vnode;

图的遍历
a. 深度优先遍历(DFS)
方法:从图的某一顶点V0出发,访问此顶点;然后依次从V0的未被访问的邻接点出发,深度优先遍历图,直至图中所有和V0相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未被访问的顶点作起点,重复上述过程,直至图中所有顶点都被访问为止

b. 广度优先遍历(BFS)
方法:从图的某一顶点V0出发,访问此顶点后,依次访问V0的各个未曾访问过的邻接点;然后分别从这些邻接点出发,广度优先遍历图,直至图中所有已被访问的顶点的邻接点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未被访问的顶点作起点,重复上述过程,直至图中所有顶点都被访问为止

生成树
定义:所有顶点均由边连接在一起,但不存在回路的图叫~
深度优先生成树与广度优先生成树
一个图可以有许多棵不同的生成树
所有生成树具有以下共同特点:
生成树的顶点个数与图的顶点个数相同
生成树是图的极小连通子图
一个有n个顶点的连通图的生成树有n-1条边
生成树中任意两个顶点间的路径是唯一的
在生成树中再加一条边必然形成回路最小生成树:
方法一:普里姆(Prim)算法
从图中的某个顶点开始,选择一条最短的边,将对应的顶点添加到顶点集合中,再从顶点集合中所有的顶点相关联的边中找出一条最短的边(边的另外一个顶点不在顶点集合中),然后将该顶点加到顶点集合中,直到所有的顶点都在顶点集合中为止
下面是AI生成的代码:

#include <stdio.h>
#include <stdbool.h>

#define MAX_VERTICES 100
#define INF 9999

int graph[MAX_VERTICES][MAX_VERTICES];
int parent[MAX_VERTICES];
int key[MAX_VERTICES];
bool mstSet[MAX_VERTICES];

int minKey(int n)
{
    int min = INF, minIndex;
    for (int v = 0; v < n; v++)
    {
        if (!mstSet[v] && key[v] < min)
        {
            min = key[v];
            minIndex = v;
        }
    }
    return minIndex;
}

void printMST(int n)
{
    printf("Edge \tWeight\n");
    for (int i = 1; i < n; i++)
    {
        printf("%d - %d \t%d\n", parent[i], i, graph[i][parent[i]]);
    }
}

void primMST(int n)
{
    for (int i = 0; i < n; i++)
    {
        key[i] = INF;
        mstSet[i] = false;
    }

    key[0] = 0;
    parent[0] = -1;

    for (int count = 0; count < n - 1; count++)
    {
        int u = minKey(n);
        mstSet[u] = true;

        for (int v = 0; v < n; v++)
        {
            if (graph[u][v] && !mstSet[v] && graph[u][v] < key[v])
            {
                parent[v] = u;
                key[v] = graph[u][v];
            }
        }
    }

    printMST(n);
}

int main()
{
    int n;
    printf("Enter the number of vertices: ");
    scanf("%d", &n);

    printf("Enter the adjacency matrix:\n");
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            scanf("%d", &graph[i][j]);
        }
    }

    primMST(n);

    return 0;
}

方法二:克鲁斯卡尔(Kruskal)算法
算法思想:设连通网N=(V,{E}),令最小生成树
初始状态为只有n个顶点而无边的非连通图T=(V,{?}),每个顶点自成一个连通分量
在E中选取代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中;否则,舍去此边,选取下一条代价最小的边
依此类推,直至T中所有顶点都在同一连通分量上为止

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值