图 学习笔记(11.21)

Posted 未定_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图 学习笔记(11.21)相关的知识,希望对你有一定的参考价值。

最近数据结构和离散数学都学习了有关图的知识,自己学习算法也对图有了更加深入的了解,下面做一下汇总,便于复习翻看。(思路是自己理解写的,代码非原创)



一、图的概念

戳一戳->

二、图的存储

先补充两种图的遍历方式:

1.邻接矩阵

思想:一个一维数组vertex[i]存顶点,一个二维数组edge[i][j]存边。
设图G=(V,E)有n个顶点,则邻接矩阵是一个n*n的方阵:
边无权值时,0表示顶点i和j之间无边,1表示有边:
e d g e [ i ] [ j ] = 0 若 ( v i , v j ) ∈ E 或 < v i , v j > ∈ E 1 否 则 edge[i][j]= \\begincases 0& &若(v_i,v_j)∈E或<v_i,v_j>∈E\\\\ 1& &否则 \\endcases edge[i][j]=01(vi,vj)E<vi,vj>E
边有权值时,wij表示顶点i到j的权值,0表示i=j,∞表示i和j之间无边:
e d g e [ i ] [ j ] = w i j 若 ( v i , v j ) ∈ E 或 < v i , v j > ∈ E 0 若 i = j ∞ 否 则 edge[i][j]= \\begincases w_ij& &若(v_i,v_j)∈E或<v_i,v_j>∈E\\\\ 0& &若i=j\\\\ ∞& &否则 \\endcases edge[i][j]=wij0(vi,vj)E<vi,vj>Ei=j
无向图的邻接矩阵是对称矩阵,即edge[i][j]=edge[j][i],有向图则不符合这个特点。邻接矩阵的主对角线为0,无向图中顶点i的度为第i行/列中非零元素的个数,有向图中顶点i的出度为第i行元素之和,入度为第i列元素之和。
注意:edge[i][j]中i和j代表顶点的顺序取决于vertex[i]中存储的顺序,如:vertex[4]=v0,v3,v1,v2,则edge[2][1]对应的边是(v1,v3)而不是(v2,v1)。
时间和空间复杂度O(n2)

const int MaxSize=10;
int visited[MaxSize];
class Mgraph

public:
    Mgraph(int a[],int n,int e);//构造函数,建立n个顶点e条边的图
    ~Mgraph() 
    void DFSTraverse(int v);//深度优先遍历图
    void BFSTraverse(int v);//广度优先遍历图
private:
    int vertex[MaxSize];
    int edge[MaxSize][MaxSize];
    int vertexNum,edgeNum;//顶点数与边数
;
Mgraph::Mgraph(int a[],int n,int e)

    int i,j,k;
    vertexNum=n;
    edgeNum=e;
    for(i=0; i<vertexNum; i++)
        vertex[i]=a[i];//顶点数组赋值
    for(i=0; i<vertexNum; i++)
        for(j=0; j<vertexNum; j++)
            edge[i][j]=0;//边数组初始化
    for(k=0; k<edgeNum; k++) //给边赋值
    
        cin>>i>>j;
        edge[i][j]=1;
        edge[j][i]=1;//无向图,若想变成有向图,只需要删除本句
    

void Mgraph::DFSTraverse(int v)

    cout<<vertex[v];//访问顶点
    visited[v]=1;//置顶点被访问过
    for(int j=0; j<vertexNum; j++)
    
        if(edge[v][j]==1&&visited[j]==0)
            DFSTraverse(j);
    

void Mgraph::BFSTraverse(int v)

    int w,j,Q[MaxSize];
    int front=-1,rear=-1;
    cout<<vertex[v];//访问顶点
    visited[v]=1;//置顶点被访问过
    Q[++rear]=v;
    while(front!=rear)
    
        w=Q[++front];//队头元素出队
        for(j=0; j<vertexNum; j++)
        
            if(edge[w][j]==1&&visited[j]==0)
            
                cout<<vertex[j];
                visited[j]=1;
                Q[++rear]=j;
            
        
    

2.邻接表

顺序存储与链式存储相结合的表示图的一种方法。
思想:图的每个顶点vi,将所有邻接于vi的顶点链成一个单链表,称为顶点vi的边表(有向图则称为出边表)
所有边表的头指针和存储顶点信息的一维数组构成了顶点表。如下图:

如果边有权值的话只需要在边表结构体里加一个变量info表示权值即可。
无向图中顶点i的边表中结点的个数为顶点i的度。
有向图中顶点 i 的出边表中结点的个数为顶点 i 的出度;各顶点的出边表中以顶点 i 为
终点的结点个数为顶点 i 的入度。
时间和空间复杂度O(n+e)

const int MaxSize = 10;
struct EdgeNode//边表结点结构体

    int adjvex;//该顶点的邻接点在顶点表中的下标
    EdgeNode *next;
;
struct VertexNode//顶点表结点结构体

    int vertex;//存放顶点信息
    EdgeNode *firstEdge;//指向边表的第一个结点
;
int visited[MaxSize];
class ALGraph

public:
    ALGraph(int a[], int n, int e); //构造函数,建立n个顶点e条边的图
    ~ALGraph();
    void DFSTraverse(int v); //深度优先遍历图
    void BFSTraverse(int v); //广度优先遍历图
private:
    VertexNode adjlist[MaxSize]; //存放顶点表的数组
    int vertexNum,edgeNum;//顶点数和边数
;
ALGraph::ALGraph(int a[],int n,int e)

    int i,j,k;
    EdgeNode *s=NULL;
    vertexNum=n;
    edgeNum=e;
    for(i=0;i<vertexNum;i++)//初始化顶点表
    
        adjlist[i].vertex=a[i];
        adjlist[i].firstEdge=NULL;
    
    for(k=0;k<edgeNum;k++)
    
        cin>>i>>j;
        s=new EdgeNode;
        s->adjvex=j;
        s->next=adjlist[i].firstEdge;
        adjlist[i].firstEdge=s;//头插法
    

ALGraph::~ALGraph()

    EdgeNode *p=NULL,*q=NULL;
    for(int i=0;i<vertexNum;i++)
    
        p=q=adjlist[i].firstEdge;
        while(p!=NULL)
        
            p=p->next;
            delete q;
            q=p;
        
    

void ALGraph::DFSTraverse(int v)

    int j;
    EdgeNode *p=NULL;
    cout<<adjlist[v].vertex;
    visited[v]=1;
    p=adjlist[v].firstEdge; //工作指针p指向顶点v的边表
    while(p!=NULL)
    
        j=p->adjvex;
        if(visited[j]==0)
            DFSTraverse(j);
        p=p->next;
    

void ALGraph::BFSTraverse(int v)

    int w,j,Q[MaxSize];
    int front=-1,rear=-1;
    EdgeNode *p=NULL;
    cout<<adjlist[v].vertex;
    visited[v]=1;
    Q[++rear]=v;
    while(front!=rear)
    
        w=Q[++front];
        p=adjlist[w].firstEdge;
        while(p!=NULL)
        
            j=p->adjvex;
            if(visited[j]==0)
            
                cout<<adjlist[j].vertex;
                visited[j]=1;
                Q[++rear]=j;
            
            p=p->next;
        
    

vector实现邻接表

const int MaxSize = 10;
struct edge//边

    int from,to,w;//起点,终点,权值
    edge(int a,int b,int c)//对边赋值
    
        from=a;
        to=b;
        w=c;
    
;
vector<edge>e[MaxSize];//e[i]存第i个结点连接的所有边。
for(int i=1;i<=n;i++)//初始化
    e[i].clear();
e[a].push_back(edge(a,b,c));//存边
for(int i=0;i<e[u].size();i++)//检索结点u的所有邻居

    ...

3.链式前向星

例题

链式前向星存图如下:u表示结点,h[u]用来定位u的第一条边,t[i].to存u的邻居结点,t[i].next定位u的下一个邻居结点。例如:u=7时,h[u]=12,即结点7的第一条边连接的邻居结点存在i=12这个位置,t[12].to=6,表示结点7的第一个邻居是结点6,t[12].next=10,即结点7的第二条边连接的邻居结点存在i=10这个位置里,t[10].to=5,即结点7的第二个邻居结点是5,依次类推,直到t[i].next=0时停止。

const int N=16000;
struct n

    int to,next, w;
t[2*N];
int h[2*N],p=1;
void add(int u,int v,int w)

    t[p].to=v;
    t[p].w=w;
    t[p].next=h[u];
    h[u]=p++;

//遍历结点i的所有邻居
for(int  i=h[u];i;i=t[i].next)
...

三、最小生成树

生成树: 包含图所有顶点的极小连通子图
生成树的代价: 生成树上各边的权值之和称为生成树的代价。
最小生成树: 生成树中代价最小的。

1.prim算法

此方法对点进行贪心操作,设所有结点集合为V,再另设一个集合U用来存最小生成树的结点。从任一点v开始,把离它最近的结点u1加入到集合U中,再从剩下的集合V-U中找到离U中某一结点最近的u2,把加到集合U中,继续上述过程直到U中加满所有结点。如下图,蓝色结点表示已经加入U中的结点,绿色表示正在比较的边。

设数组adjvex[n]存结点,lowcost[n]存每个结点最短边权值,lowcost[v]=0表示顶点v已加入最小生成树中(加入到U中)。
怎么把点加入到集合U中呢?是每一次都把V-U中的所有结点与U中所有结点相连的边都比较一遍吗?你会发现每一次比较都会有重复比较的边,极浪费时间。怎么办呢?
聪明的你一定想到了动态规划,不过这里不用DP数组来实现。我们考虑最初把已知结点v加入到集合U中,lowcost[v]=0,表示v到v的最短边为0,其余结点的最短边在没有比较的情况下都假定最短边是与结点v相连,即adjvex[i]=v,每个结点对应最短边lowcost[i]等于结点i与v的边的权值,这就是初始化。
接下来加点到U中,我们找V-U中所有结点到结点v的边中权值最小的,把对应的结点j1加入集合U中,代码对应就是找到当前lowcost数组中最小的lowcost[j],让其等于0;因为集合U的改变,V-U中到U中结点的最短边可能会改变,集合V-U结点最短边对应的邻接点也可能会变,需要更新两个数组。U中目前已经有结点j1,v,集合V-U中的任何一个结点到集合U

以上是关于图 学习笔记(11.21)的主要内容,如果未能解决你的问题,请参考以下文章

11.21团队总结

学习笔记:python3,代码片段(2017)

11.21

[原创]java WEB学习笔记61:Struts2学习之路--通用标签 property,uri,param,set,push,if-else,itertor,sort,date,a标签等(代码片段

11.15-11.21大学生Python学习社区总结+优秀社区成员点名表扬&&技术书籍和CSDN定制背包奖励~

11.15-11.21大学生Python学习社区总结+优秀社区成员点名表扬&&技术书籍和CSDN定制背包奖励~