相关概念

图: 由顶点V(G1)={v1,v2,v3}和边E(G1)={<v1,v2>,<v2,v1>,<v2,v3>}组成,其中边中<v1,v2>,v1为起点,v2终点
有向完全图: 边的数量n(n-1)
无向完全图: 边的数量n(n-1)/2
邻接点: 一个顶点周围的顶点(只要有边连接),都是它的邻接点
度: 进度和出度之分,就是边的方向
根: 在有向图中,一条路径的起点称为根
连通图: 若任意两个不同的顶点都是连通的(有路径,不管路径长度是多少),则此图称为连通图
极大连通分量: 显然连通图的极大连通分量只有一个,即本身
有向图: 每条边都是有方向的

图的储存

用邻接矩阵表示法,比如一个图五个顶点,那么将存在5*5的矩阵,1来表示两个点之间有连接,0表示没有
如果图是网络,那么1变成权值
在这里插入图片描述
邻接矩阵表示法:

/*
 * 邻接矩阵表示法
*/
#include<iostream>
using namespace std;
#define n 4//图的顶点数
#define e 5//图的边数
typedef char vextype;//顶点的数据类型
typedef float adjtype;//权值类型
typedef struct
{
    vextype vexs[n];
    adjtype arcs[n][n];
}grath;
void createGrath(grath *g)//建立无向网络图,先确定顶点下来,初始化,然后在边上加上权值就好
{
    for(int i=0;i<n;i++)cin>>g->vexs[i];
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            g->arcs[i][j]=0;
        }
    }
    for(int i=0;i<e;i++)
    {
        int i1,i2;
        adjtype w;
        cin>>i1>>i2>>w;
       g->arcs[i1][i2]=w;
       g->arcs[i2][i1]=w;
    }
}
void display(grath *g)
{
    for(int i=0;i<e;i++)//输出边字符
    {
        cout<<g->vexs[i]<<"\t";
    }
    cout<<endl;
    for(int i=0;i<n;i++)//输出矩阵
    {
        for(int j=0;j<n;j++)
        {
            cout<<g->arcs[i][j]<<"\t";
        }
        cout<<endl;
    }
}
static int visit[n];//深度遍历时需要
void DFS(grath *g,int i)//深度遍历,输出节点的信息,i为出发的节点
{
    cout<<"node:"<<g->vexs[i]<<endl;
    visit[i]=1;//表示已经访问过
    for(int j=0;j<n;j++)
        if(!visit[j]==1&&g->arcs[i][j]==1)
            DFS(g,j);

}
int main()
{
    grath g;
    createGrath(&g);
    display(&g);
    DFS(&g,1);
    return 0;
}

在这里插入图片描述
邻接表表示法:

/*
 * 邻接表表示法(顶点表->边表)
 *
*/
#include<stdlib.h>
#include<string>
#include<sstream>
#include<iostream>
using namespace std;
#define n 4
#define e 5
typedef char vextype;
typedef struct node
{
    int adjvex;
    struct node* next;
}edgenode;//边表节点
typedef struct
{
    vextype vertex;
    edgenode *link;
}vexnode;//顶点表节点
vexnode gg[n];

void creatGrath(vexnode ga[])
{
    int i, j, k;;
    edgenode *s=NULL;
    cout << "input top node information:\n";
    for (i = 0;i < n;i++) //读入顶点信息,建立了顶点表节点
    {
        cin >> ga[i].vertex;//top node information
        ga[i].link = NULL;
    }
    //cout << "node and node relation:\n";
    for (k = 0;k < e;k++)//建立边表(主要的方法:将边表节点记录节点的序号,然后然后会找到两个相应的顶点节点进行插入)
    {                    //就好比节点1和节点2有边,然后输入的值为1,2,那会在顶点节点1进行2节点插入
                         //在顶点节点2进行节点1的插入
        /*注意:因为储存时输入的边是不算0的,但是这里面顶点从0开始*/
        cin >> i>>j;
        s =new edgenode;
        s->adjvex = j;//邻节点
        s->next = ga[i-1].link;//链
        ga[i-1].link = s;
        s = new edgenode;
        s->adjvex = i;
        s->next = ga[j-1].link;
        ga[j-1].link = s;
    }
}
/*
 * 显示建立的邻接表,方法:创建n的字符串,存放顶点和节点的信息
*/
string str[n];
void displayGrath(vexnode ga[])
{
    edgenode *p;//保证了next的不变性
    for(int i=0;i<n;i++)
    {
        p=ga[i].link;
        str[i]=ga[i].vertex;
        str[i]+=":";
        while(p!=NULL)
        {
            str[i]+="-> ";
            str[i]+='0'+p->adjvex;
            p=p->next;

        }
        str[i]+="-> NULL";
        cout<<str[i]<<endl;
    }
}
/*
 * 深度遍历
 * 遍历顶点,从顶点节点开始找,下一个如果存在节点,且标志的下一个位置没有访问过,那就出发到节点标志的顶点。
 * 如果下一个节点为空或者已经访问过,递归返回上层。
 * --i是因为顶点从0存储,但是i是从1开始
*/
int visit[n];
void DFSL(vexnode ga[],int i)
{
    --i;
    edgenode *p;
    p=ga[i].link;
    cout<<"node:"<<ga[i].vertex<<endl;
    visit[i]=1;
    while(p!=NULL)
    {
        if(!visit[p->adjvex-1]){DFSL(ga,p->adjvex);}
        p=p->next;
    }
}
int main()
{
    vexnode ga[n];
    creatGrath(ga);
    displayGrath(ga);
    displayGrath(ga);
    DFSL(ga,1);
    return 0;
}

在这里插入图片描述

最小生成树

生成树是极小连通图,边数为n-1,如果多一条边就会变成回路,少一条边就不是连通图

把生成树各边的值的权的总和称为生成树的权,权值最小时称为最小生成树。
在这里插入图片描述

/*
 * 实现最小生成树算法
 * 1.创建grath,由邻接矩阵储存
 * 2.最终的结果是连接的顺序出现,如1-2-3,表示1和2相连,2和3相连
 * 算法介绍:
 * 1.任意选取其中一个点,生成了n-1个边,如果他们之间没有边则权值为0
 * 2.找到权值最小的边,那就找到了下一个节点所在地,下一个节点再寻找周围的边,如果存在和上一个节点连通的边,
 * 比较大小,如果小,则去掉上一个节点与所找节点的边,寻找最小边进入下一个节点,t[k]里面k++。
 * 3.最终的结果存放在t里面(n-1条边的信息,即最小生成树)
*/
/*
 * 例子:6个顶点,10条边
 * 邻接矩阵图
 * 0	6	1	5	0	0
 * 6	0	5	0	3	0
 * 1	5	0	7	5	4
 * 5	0	7	0	0	2
 * 0	3	5	0	0	6
 * 0	0	4	2	6	0
 * 输入的数据:
 * 1 2 3 4 5 6
 * 0 1 6
 * 0 2 1
 * 0 3 5
 * 1 4 3
 * 1 2 5
 * 2 4 5
 * 2 3 7
 * 3 5 2
 * 2 5 4
 * 4 5 6
 *
 * 结果:
 *创建图,1 2 3 4 5 6为节点信息,其余为边如0 1 2表示从节点0到节点1的边的权为
 * 1 2 3 4 5 6
 * 0 1 6
 * 0 2 1
 * 0 3 5
 * 1 4 3
 * 1 2 5
 * 2 4 5
 * 2 3 7
 * 3 5 2
 * 2 5 4
 * 4 5 6
 * 最小生成树算法开始
 * 结果是(邻接矩阵表示),后面加上了边的信息:
 * 0	0	1	0	0	0
 * 0	0	0	0	3	0
 * 1	0	0	0	5	4
 * 0	0	0	0	0	2
 * 0	3	5	0	0	0
 * 0	0	4	2	0	0
 * 021
 * 254
 * 532
 * 245
 * 413

*/
#include<iostream>
using namespace std;
#define n 6//图的顶点数
#define e 10//图的边数
typedef char vextype;//顶点的数据类型
typedef float adjtype;//权值类型
typedef struct
{
    vextype vexs[n];
    adjtype arcs[n][n];
}grath;
void createGrath(grath *g)//建立无向网络图,先确定顶点下来,初始化,然后在边上加上权值就好
{
    for(int i=0;i<n;i++)cin>>g->vexs[i];
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            g->arcs[i][j]=101;
        }
    }
    for(int i=0;i<e;i++)
    {
        int i1,i2;
        adjtype w;
        cin>>i1>>i2>>w;
       g->arcs[i1][i2]=w;
       g->arcs[i2][i1]=w;
    }
}
void display(grath *g)
{
    for(int i=0;i<e;i++)//输出边字符
    {
        cout<<g->vexs[i]<<"\t";
    }
    cout<<endl;
    for(int i=0;i<n;i++)//输出矩阵
    {
        for(int j=0;j<n;j++)
        {
            cout<<g->arcs[i][j]<<"\t";
        }
        cout<<endl;
    }
}
/*
 * 定义一种数据结构,存放边的值<v1,v2,w>
 *
*/
struct edgenode
{
  int i,j;//行列,也就是v1,v2的位置
  float w;//权值
};
edgenode t[n-1];
void PRIM(grath *g)
{
    //1.建立n-1个边edgenode,T[n-1]存放节点和权值
    for(int i=0;i<n-1;i++)
    {
        t[i].i=0;
        t[i].j=i+1;
        t[i].w=g->arcs[0][i+1];

    }
    //2.修改t[n-1]得值,将找到的合适的节点存放下来,然后k++
    for(int k=0;k<n-1;k++)
    {
        //2.1找到t里面最小的权值,记录下位置
        int min=100;
        int location=0;
        for(int j=k;j<n-1;j++)
        {
            if(t[j].w==0)continue;
            if(t[j].w<min)
            {
                min=t[j].w;
                location=j;
            }
        }//现在t[location]是最短边
       //2.2最短边进入t里面保存不变
        edgenode ed=t[location];t[location]=t[k];t[k]=ed;//找到最小的那个,自然存放在t里面,故交换位置,那就可以t下标位置跳过这个位置
        int v=t[k].j;//现在的节点的位置
        //2.3将t更新,t的路径大就用小的取代
        for(int j=k+1;j<n-1;j++)
        {
            float d=g->arcs[v][t[j].j];
            if(d<t[j].w)
            {
                t[j].w=d;
                t[j].i=v;//由于两个边通向那个节点,所以改变那个节点的i值,指向同一个,那就相当于删去一个路径,只剩一条了
            }
        }
    }
}
/*
 * 输出最小生成树的邻接矩阵
*/
void displayPRIM(grath *g,edgenode t[])
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            g->arcs[i][j]=0;
        }
    }
    for(int i=0;i<n-1;i++)
    {
        g->arcs[t[i].i][t[i].j]=t[i].w;
        g->arcs[t[i].j][t[i].i]=t[i].w;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            cout<<g->arcs[i][j]<<"\t";
        }
        cout<<endl;
    }
for(int i=0;i<n-1;i++)
    cout<<t[i].i<<t[i].j<<t[i].w<<endl;
}
int main()
{
    grath g;
    cout<<"创建图,1 2 3 4 5 6为节点信息,其余为边如0 1 2表示从节点0到节点1的边的权为\n";
    createGrath(&g);
    cout<<"最小生成树算法开始\n";
    PRIM(&g);
    cout<<"结果是(邻接矩阵表示),后面加上了边的信息:\n";
    displayPRIM(&g,t);
    return 0;
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值