图论二:图的存储

一、邻接矩阵:就是一个二维数组

特点:对称(矩阵有对称性),空间代价大(空间需求为O(|v|^2)),适用于稠密图,否则空间浪费较大。

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 120;
const int INF = 0x3fff;
int a[maxn][maxn],n;
void Init()
{
    int i,j;
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        a[i][j]=INF;
}
void Print()
{
    int i,j;
    for(i=1;i<=n;i++)
    {
        cout<<i<<"的邻接点有:"; 
        for(j=1;j<=n;j++)
            if(a[i][j]!=INF) cout<<"a["<<i<<"]["<<j<<"]="<<a[i][j]<<" ";
        cout<<endl;
    }
}
int main(void)
{
    int i,j,x,m,y,z;
    cin>>n>>m;
    Init();
    for(i=0;i<m;i++)
    {
        cin>>x>>y>>z;
        a[x][y]=a[y][x]=z;
    }
    Print();
    return 0;
}
/*
测试数据:
5 4
1 2 1
2 3 4
4 5 7 
4 3 9
*/
View Code

二、邻接矩阵:散列表或者多重表

特点:适用于稀疏矩阵,存储空间较小为O(2*|E|)。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct Node{
    int data,dis;
    struct Node *next;
};

struct LNode{
    struct Node *First;
    struct LNode *NEXT;
};

typedef struct LNode *Lin;
int vis[120],m,n;

Lin Find(int x,Lin T)
{
    Lin p=T;
    while(p!=NULL)
    {
        if(p->First->data==x) break;
        p=p->NEXT;
    }
    return p;
}

void Insert(int x,int dis,struct Node* T)
{
    struct Node* tp=T;
    while(tp->next!=NULL) tp=tp->next;
    struct Node* p=(struct Node*)malloc(sizeof(struct Node));
    p->data=x;
    p->dis=dis;
    p->next=tp->next;
    tp->next=p;
    //return T;
}

void dfs(Lin T,int fa,int dis)
{
    if(T==NULL) return ;
    if(fa) printf("深搜遍历图的一条边:(%d->%d),边的长度为: %d
",fa,T->First->data,dis);
    fa=T->First->data;
    for(struct Node* p=T->First->next;p!=NULL;p=p->next)
    {
        Lin tp=Find(p->data,T);
        if(vis[p->data]==0)
        {
            vis[p->data]=1;
            dfs(tp,fa,p->dis);
            vis[p->data]=0;
        }
    }
}

int main(void)
{
    int i,j,x,y,dis;
    Lin T,p,tp;
    T=(Lin)malloc(sizeof(struct LNode));
    T->NEXT=NULL;
    p=T;
    printf("请输入图的顶点数和边数:
");
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
    {
        tp=(Lin)malloc(sizeof(struct LNode));
        tp->First=(struct Node*)malloc(sizeof(struct Node));
        tp->First->data=i;
        tp->First->next=NULL;
        tp->NEXT=p->NEXT;
        p->NEXT=tp;
        p=p->NEXT;
    }
    
    printf("请输入图的边:
");
    for(i=0;i<m;i++)
    {
        scanf("%d%d%d",&x,&y,&dis);
        p=Find(x,T);
        Insert(y,dis,p->First);
        p=Find(y,T);
        Insert(x,dis,p->First);
    }
    memset(vis,0,sizeof(vis));
    dfs(T->NEXT,0,0);
    return 0;
}

/*
测试样例: 
5 5
1 2 34
2 3 45
3 4 13
1 4 66
5 1 29
*/
View Code

三、十字链表(适用于有向图)

 1、定义:是一种链式存储结构,可以视为邻接表和逆邻接表的结合,既可以求入度,也可以求出度,十分方便。

 解释:

(1)普通的邻接表可以求出入度,普通的逆邻接表可以求出出度,而十字链表可以求出入度+出度。

(2)十字链表对于有向图来说还是非常方便的既可以正向遍历节点,也可以反向进行,类似于双向链表。

2、存储结构:

(1)边节点:每个边界点存储4个变量:tailvex(一条边起点的ID),headvex(一条边终点的ID),taillink(一条边入边的指针),

headlink(一条边出边的指针)。(还可以有存储边的权值的数据)。

(2)点节点:有两个指针:First_IN(表示第一个入度的节点),First_Out(表示第一个出度的节点),data(表示这个节点的编号)。

每个顶点的信息,作为边之间传值的中转站,可以从一条边跑到另一条边。

(3)图结构:VertexNum(点的数量),EdgeNum(边的数量),cur数组(记录图中每个节点的信息)。

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int maxn = 1200;

struct EdgeNode{ //边结构体 
    int tailvex,headvex;
    struct EdgeNode *taillink,*headlink;
};
typedef struct EdgeNode* Edge;

struct VertexNode{ //点结构体 
    int data;
    Edge First_IN,First_OUT;
}; 
typedef struct VertexNode* Vertex;

struct GraphNode{ //图的总结构 
    int VertexNum,EdgeNum; 
    struct VertexNode cur[maxn];
};
typedef struct GraphNode* Graph;

void Create_Graph(Graph &G) //构造一个图 
{
    int i,x,y,z;
    G=(Graph)malloc(sizeof(struct GraphNode));
    scanf("%d%d",&G->VertexNum,&G->EdgeNum);
    for(i=1;i<=G->VertexNum;i++)
    {
        G->cur[i].data=i;
        G->cur[i].First_IN=NULL;
        G->cur[i].First_OUT=NULL;
    }
    
    for(i=1;i<=G->EdgeNum;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        Edge e=(Edge)malloc(sizeof(struct EdgeNode));
        e->tailvex=x;  //out是出度 ,构建邻接表 
        e->taillink=G->cur[x].First_OUT;
        G->cur[x].First_OUT=e;
        
        e->headvex=y; //in是入度,构建逆邻接表 
        e->headlink=G->cur[y].First_IN;
        G->cur[y].First_IN=e; 
    }
}

void Show(Graph G) //展示图的入度和出度。 
{
    int i,num;
    Edge e;
    for(i=1;i<=G->VertexNum;i++)
    {
        printf("%d节点的:",G->cur[i].data);
        num=0;
        e=G->cur[i].First_IN;
        while(e!=NULL)
        {
            num++;
            e=e->headlink;
        }
        printf("入度是:%d	",num);
        
        num=0;
        e=G->cur[i].First_OUT;
        while(e!=NULL)
        {
            num++;
            e=e->taillink;
        }
        printf("出度是:%d
",num); 
    }
}

int main(void)
{
    Graph G;
    Create_Graph(G);
    Show(G);
    return 0;
}

/*
测试数据: 
5 4
1 2 3
2 3 2
3 4 1
4 5 5
*/
View Code

四、邻接多重表

参考文章:http://www.cnblogs.com/Trojan00/p/8964609.html

 思路:邻接多重表主要用于存储无向图,每条边的边界点分别在以该边所依附的两个顶点为头结点的链表中,对于已经找到过的边要做标记。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int maxn = 1200;
int vis[maxn]={0};
struct EdgeNode{ //图的边结构 
    int weight,mark;
    int ivec,jvex;
    struct EdgeNode *ilink,*jlink; 
};
typedef struct EdgeNode* Edge;

struct VertexNode{ //图的点结构 
    int id;
    Edge Firstarc;
};
typedef struct VertexNode* Vertex;

struct GraphNode{ //图的结构 
    VertexNode cur[maxn];
    int VertexNum,EdgeNum;
};
typedef struct GraphNode *Graph;

int Locate(Graph G,int pos)
{
    for(int i=1;i<=G->VertexNum;i++)
    if(G->cur[i].id==pos) return i;
    return -1;
}
 
Graph Create()
{
    int i,x,y,z;
    Graph G=(Graph)malloc(sizeof(struct GraphNode));
    cout<<"请输入图的节点数目和边的数目:"<<endl; 
    cin>>G->VertexNum>>G->EdgeNum;
    
    for(i=1;i<=G->VertexNum;i++) //初始化图的每一个节点 
    {
        G->cur[i].id=i;
        //G->cur[i].Firstarc=(Edge)malloc(sizeof(struct EdgeNode));
        G->cur[i].Firstarc=NULL;
    }
    
    for(i=1;i<=G->EdgeNum;i++)
    {
        cin>>x>>y>>z;
        int t1=Locate(G,x);
        int t2=Locate(G,y);
        if(t1<0||t2<0) printf("ERROR
");
        Edge tp=(Edge)malloc(sizeof(struct EdgeNode));
        tp->ivec=t1;
        tp->jvex=t2;
        tp->weight=z;
        
        tp->mark=0;
        tp->ilink=G->cur[t1].Firstarc;
        tp->jlink=G->cur[t2].Firstarc;
        G->cur[t1].Firstarc=tp;
        G->cur[t2].Firstarc=tp;
    }
    return G;
}

void Dfs(Graph G,int x)
{
    cout<<G->cur[x].id<<" ";
    Edge p=G->cur[x].Firstarc;
    vis[x]=1;
    while(p!=NULL)
    {
        int i=(p->ivec==x?p->jvex:p->ivec);
        if(!vis[i]) Dfs(G,i);
        p=(p->ivec==x?p->jlink:p->ilink);
    }
}

int main(void)
{
    Graph G=Create();
    Dfs(G,1);
    return 0;
}

/*
4 5
1 2 1
2 3 1
3 4 2
2 4 3
1 4 2

*/
View Code
原文地址:https://www.cnblogs.com/2018zxy/p/10101901.html