图、树的建立

一、邻接矩阵:
内存占用较高,仅适用于0<=n<=1000的图,在简单的图算法题目中较为常见。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=0x7fffffff;
const int maxn=1005;
int n,_num;
int a[maxn][maxn];//储存图
int main(void)
{
    while(scanf("%d%d",&n,&_num)!=EOF)
    {
        //初始化
        memset(a,0,sizeof(a));
        memset(a,-1,sizeof(a));  //a[i][j]=-1;

        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            a[i][j]=inf;

        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            a[i][j]=-inf;

        int pre,_next,vi;
     
        //有向图建立
        for(int i=1;i<=_num;i++)
        {
            scanf("%d%d%d",&pre,&_next,&vi);
            a[pre][_next]=vi;
        }

        //无向图建立
        for(int i=1;i<=_num;i++)
        {
            scanf("%d%d%d",&pre,&_next,&vi);
            a[pre][_next]=vi;
            a[_next][pre]=vi;
        }

    }
    return 0;
}

二、邻接链表:
使用vector模拟邻接链表,较邻接矩阵更加节省内存空间,内存利用率高,简单好写。
是处理图或树算法题的最经常用的存图方式。能处理1e5数据。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int inf=0x7fffffff;
const int maxn=100005;
int n,m;
//节点及边权值
struct node
{
    int x;//节点
    int vi;//边权值
    node(){}
    node(int a,int b)
    {
        x=a;
        vi=b;
    }
};
//邻接表
vector<node>vc[maxn];
//有向图入度
int _num[maxn];

//初始化
void init(int n)
{
    for(int i=1;i<=n;i++)
    {
        vc[i].clear();
        _num[i]=0;
    }
    return ;
}

int main(void)
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        //初始化
        init(n);

        int pre,_next,vi;

        //有向图建表
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&pre,&_next,&vi);
            vc[pre].push_back(node(_next,vi));
            _num[_next]++;
        }

        //无向图建表
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&pre,&_next,&vi);
            vc[pre].push_back(node(_next,vi));
            vc[_next].push_back(node(pre,vi));
        }
    }
    return 0;
}

三、链式前向星:
储存稀疏图,边集,时间效率优于vector。

对于链式前向星,可以由结构体+数组实现,也可以完全由数组实现。
head数组的大小为图或树的节点数的个数。
对于树来说,若有向, 其余各数组大小均应该开到节点数大小;
若无向, 其余各数组大小均应该开到节点数的二倍大小。
对于图来说,若有向, 其余各数组大小均应该开到边数量大小;
若无向, 其余各数组大小均应该开到边数量二倍大小。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<stack>
#define ll long long
using namespace std;
const int maxn=100008;
const int inf=0x7fffffff;
const int mod=1000000007;
int head[maxn],nt[maxn],ver[maxn],edge[maxn];
//若建立无向图则应采取以下写法
//int head[maxn],nt[2*maxn],ver[2*maxn],edge[2*maxn];

int tot=0;
// int tot=1;
void add(int x,int y,int z)
{
    //head与nt数组中保存的是ver数组的下标
    //相当于指针,其中0(-1)表示指向空
    //ver数组储存的是每条边的终点,是真实的图数据
    //edge保存的是每一条边的权值

    ver[++tot]=y,edge[tot]=z;//真实数据
    nt[tot]=head[x],head[x]=tot;//在表头x处插入
    return ;
}

//访问从x出发的所有边
void fi(int x)
{
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i],z=edge[i];
        //找到一条x——》y的有向边,权值为z
    }
    return ;
}

int main(void)
{
    //初始化为0,或者-1,代表为空的数据
    memset(head,0,sizeof(head));
    memset(head,-1,sizeof(head));
    int n,m;//n个节点,m条边
    int pre,_next,vi;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&pre,&_next,&vi);
        //有向边
        add(pre,_next,vi);
        //无向边
        add(_next,pre,vi);
    }
    //查询每一条边出发能到达的节点
    for(int i=1;i<=n;i++)
    {

        fi(i);
    }
    return 0;
}

以后的写代码的时候尽量适应用第三种建图方式。

猜你喜欢

转载自blog.csdn.net/zhaoxinxin1234/article/details/89410523