学习笔记:图

本文介绍了图的基本概念,包括无向图和有向图的定义,顶点的度以及完全图的概念。讨论了图的存储方式,如邻接矩阵和邻接表,并详细阐述了深度优先搜索(DFS)和广度优先搜索(BFS)两种图的遍历算法。此外,还探讨了图的应用,包括Prim和Kruskal算法用于构造最小生成树,以及Dijkstra和Floyd算法解决最短路径问题。

思维导图

在这里插入图片描述

图的定义

无论多么复杂的图都是由顶点边构成的。

在无向图中,若存在一条边(i,j),则称顶点i和顶点j为该边的两个端点,并称他们互为临接点

在有向图中,若存在一条有向边<i,j>,则顶点i和顶点j分别称为起始端点终止端点

在无向图中,一个顶点所关联的边的数目称为该顶点的度

在有向图中,顶点的度又分为入度出度

在无向图中,任意两点都存在一条边,有向图中任意两个顶点都存在方向相反的边,则该图成为完全图

顶点i和顶点有路径,则i和j是连通的

图中任意一对的顶点之间都有路径,那么就是强连通图

图的存储

临界矩阵

用一个一维数组存放顶点集合,一个二维数组存放边的信息(称为邻接矩阵),边是可以带权值的

#define MAXVEXNUM 100 //点,边
typedef char VexType; //点的类型
typedef int ArcCell; //边的类型
typedef struct
{
    VexType vexs[MAXVEXNUM];            //点的集合
    ArcCell arcs[MAXVEXNUM][MAXVEXNUM]; //边的集合
    int vexNum, arcNum;                 //点和边的个数
} MyGraph;

对无向图而言,邻接矩阵一定是对称的,而且主对角线一般为零。

邻接表

图的邻接表存储方法一种顺序分配和链式分配相结合的存储结构。如这个表头结点所对应的顶点存在相邻顶点,则把相邻顶点依次存放于表头结点所指向的单向链表中。

#define MAXVEXNUM 100    //点
typedef char VertexType; //顶点的类型
typedef int EdgeType;    //边的类型
typedef struct EdgeNode  //边表结点
{
    VertexType data; //点
    EdgeType weight; // 权值
    EdgeNode *next;  //下一个点
} EdgeNode;
typedef struct VexNode //顶点表结点
{
    VertexType data;     //顶点
    EdgeNode *firstEdge; //指向第一个临界点
}VexList[MAXVEXNUM];

图的遍历

dfs

在搜索其余的路径结果之前必须先完整地搜索单独的一条路径。采用栈

bfs

每次拓展当前结点的所有出度。它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。采用队列。

图的应用

最小生成树

Prim

每次从已经生成的树中,向其他点拓展一条最短边。

for (i = 1; i < Vexnum; i++)
{
    min = MAX;
    //求出与集合U权值最小的点 权值为0的代表在集合U中
    for (int j = 0; j < Vexnum; j++)
    {
        if (cost[j] != 0 && cost[j] < min)
        {
            min = cost[j];
            k = j;
        }
    }
    mincost += min;//累加
    //更新最小边
    for (int j = 0; j < Vexnum; j++)
    {
        if (cost[j] != 0 && a[k][j] < cost[j])
        {
            cost[j] = k;
            cost[j] = a[k][j];
        }
    }
}

Kruskal

按边的权值排序,用并查集判断是否在同一个集合。

struct Edge
{
    int x, y;
    int data;
} a[EMAX];
bool cmp(Edge x, Edge y) //排序
{
    return x.data < y.data;
}
int Find(int x)//查询所在集合
{ 
    if (x != Fa[x])
        Fa[x] = Find(Fa[x]);
    return Fa[x];
}
viod Uni(int x, int y)//合集
{ 
    Fa[Find(x)] = Find(y);
}
void slove()
{
    sort(a, a + En, cmp);
    int d = 0;
    for (int i = 0; i < En; ++i)
    {
        if (Find(a[i].x) != Find(a[i].y))//判断是否同一集合
        { 
            d++;
            Uni(Find(a[i].x), Find(a[i].y)) //合集
        }
        if(d==n-1)
            break;
    }
}

最短路径

Dijkstra

Dijkstra算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。

for (i = 1; i <= n; i++)
{
    Vmin = MAX;//初始化最小值
    k = 0;
    for (j = 1; j <= n; j++)//找到未访问节点中d[j]值最小的那个节点,
        if (!p[j] && d[j] < Vmin)
        {
            Vmin = d[j];
            k = j;
        }
    p[k] = 1; //标记第k个节点已经访问过了
    for (j = 1; j <= n; j++)
        if (a[k][j] != 0 && !p[j] && d[j] > d[k] + a[k][j])
            d[j] = d[k] + a[k][j];
}

Floyd

Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。

for (k = 0; k < Vernum; ++k)
    for (i = 0; i < Vernum; ++i)
        for (j = 0; j < Vernum; ++j)
            if (a[i][k] + a[k][j] < a[i][j]) //i到k的距离+k到j的距离 比较 i到j的距离,
                a[i][j] = a[i][k] + a[k][j]; //更新
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值