图结构及其应用

#include <iostream>
#include <stdio.h>
#include <malloc.h>
#include <fstream>
#include <cstdlib>
#include <queue>
#include <string.h>
using namespace std;
#define MAX_VERTEX_NUM   20
#define N 100
bool visit[N];  //访问标记数组是全局变量
int dfn[N];  //顶点的先深编号
int count = 1;
int FLAG = 99999;
int in_order[N];
//无向图
struct MTGragh
{
    int vertex [N]; //顶点表
    int edge[N][N];//邻接矩阵—边表, 可视为边之间的关系
    int n, e; //图的顶点数与边数
};
//正向链接表
typedef struct node  //边表结点
{
    int adjvex; //邻接点域(下标)
    int  cost; //边上的权值
    struct node *next; //下一边链接指针
} EdgeNode;
typedef struct  //顶点表结点
{
    int  vertex; //顶点数据域
    EdgeNode * firstedge;//边链表头指针
} VertexNode;
typedef struct  //图的邻接表
{
    VertexNode vexlist [N];
    int n,e;  //顶点个数与边数
} AdjGraph;
//十字链表
typedef struct ArcBox
{
    int  tailvex, headvex; //该弧的尾和头顶点的位置
    int  cost; //该弧的信息
    struct ArcBox * hlink, * tlink;  //分别为弧头相同和弧尾相同的弧的链域
} ArcBox;
typedef struct VexNode
{
    int data; //顶点值
    ArcBox * firstin, * firstout;  //分别指向该顶点第一条入弧和出弧
} VexNode;
typedef struct
{
    VexNode  xlist[MAX_VERTEX_NUM]; //表头向量
    int n, e;       //有向图的当前顶点数和弧数
} OLGraph;
//无向图的邻接多重表
typedef enum {unvisited, visited} VisitIf;
typedef struct EBox
{
    VisitIf   mark; //访问标记
    int ivex, jvex; //该边依附的两个顶点的位置
    struct EBox   * ilink, * jlink; //分别指向依附这两个顶点的下一条边
    int cost; //该边信息
} EBox;
typedef struct VexBox
{
    int   data;
    EBox * firstedge; //分别指向该顶点第一条入弧和出弧
} VexBox;
struct AMLGraph
{
    VexBox adjmulist[MAX_VERTEX_NUM];
    int n,e; //无向图的当前顶点数和边数
};
void  DFS(OLGraph *G, int v);
void  Rev_DFS(OLGraph *G, int v);
//建立图的邻接矩阵
int CreateMGragh(MTGragh *G,int c[N],int flag,int sum)
{
    int i, j;
    G->n=c[1];
    for (i=0; i<G->n; i++) //2.读入顶点信息,建立顶点表
        G->vertex[i]=i;
    for (i=0; i<G->n; i++)
        for (j=0; j<G->n; j++)
            G->edge[i][j]=0; //3.邻接矩阵初始化
    int a,b;
    int temp=0;
    i=2;
    if(flag==0)
    {
        while(i<sum)
        {
            a=c[i];
            i++;
            b=c[i];
            i++;
            G->edge[a][b] = c[i];
            G->edge[b][a] = c[i];
            temp++;
            i++;
        }
    }
    else
    {
        while(i<sum)
        {
            a=c[i];
            i++;
            b=c[i];
            i++;
            G->edge[a][b] = c[i];
            //G->edge[b][a] = c[i];
            temp++;
            i++;
        }
    }
    G->e=temp;
    return G->e;
}
//输出无向图的邻接矩阵
void putMgraph(MTGragh G)
{
    cout<<"无向图的邻接矩阵:"<<endl;
    for(int i=0; i<G.n; i++)
    {
        cout<<i<<": ";
        for(int j=0; j<G.n; j++)
        {
            cout<<G.edge[i][j]<<" ";
        }
        cout<<endl;
    }
}
//建立图的链接表
AdjGraph CreateGraph(AdjGraph G,int c[N],int k)
{
    G.n=c[1]; G.e=k;int j=2;
    for(int i = 0; i < G.n; i++)  //2.建立顶点表
    {
        G.vexlist[i].vertex=i;  //2.1输入顶点信息
        G.vexlist[i].firstedge = NULL;//2.2边表置为空表
    }
    for ( int i = 0; i < k; i++)//逐条边建立边表
    {
        int tail = c[j];
        j++;
        int head=c[j];
        j++;
        int weight = c[j];
        j++;
        EdgeNode * p = new EdgeNode; //建立边结点
        p->adjvex = head;
        p->cost = weight; //设置边结点
        p->next = G.vexlist[tail].firstedge;  //链入第 tail 号链表的前端
        G.vexlist[tail].firstedge = p;
    }
    return G;
}
//输出有向图的链接表
void putGraph(AdjGraph A)
{
    cout<<"有向图的链接表:"<<endl;
    for(int i=0; i<A.n; i++)
    {
        cout<<A.vexlist[i].vertex<<" ";
        if(A.vexlist[i].firstedge!=NULL)
        {
            EdgeNode *temp=A.vexlist[i].firstedge;
            for(; temp!=NULL; temp=temp->next)
            {
                cout<<temp->adjvex<<","<<temp->cost<<"  ";
            }
        }
        cout<<endl;
    }
}
//采用十字链表存储表示,构造有向图
void CreateDG(OLGraph  &G,int c[N],int k)
{
    G.n=c[1];
    G.e=k;
    for (int i = 0; i < G.n; i++)
    {
        //构造表头向量
        G.xlist[i].data=i; //输入顶点值
        G.xlist[i].firstin = NULL;
        G.xlist[i].firstout = NULL;   //初始化指针
    }
    int j=2;
    for (int k = 0; k < G.e; k++)
    {
        //输入各弧并构造十字链表
        int v1=c[j];//输入一条弧的始点和终点
        j++;
        int v2=c[j];
        j++;
        int weight=c[j];
        j++;
        ArcBox *p = new ArcBox;//假定有足够空间
        //正向表
        p->headvex=v2;
        p->cost=weight;
        p->hlink=G.xlist[v1].firstin;
        G.xlist[v1].firstin=p;
        //逆向表
        p = new ArcBox;
        p->tailvex=v1;
        p->cost=weight;
        p->tlink=G.xlist[v2].firstout;
        G.xlist[v2].firstout=p;
    }
}
//输出有向图的十字链表
void putDG(OLGraph G)
{
    cout<<"有向图的十字链表:"<<endl;
    for(int i=0; i<G.n; i++)
    {
        cout<<G.xlist[i].data<<" ";
        cout<<"正向"<<"  ";
        if(G.xlist[i].firstin!=NULL)
        {
            ArcBox *temp = G.xlist[i].firstin;
            for(; temp!=NULL; temp=temp->hlink)
                cout<<temp->headvex<<","<<temp->cost<<"  ";
        }
        cout<<"逆向"<<"  ";
        if(G.xlist[i].firstout!=NULL)
        {
            ArcBox *temp1 = G.xlist[i].firstout;
            for(; temp1!=NULL; temp1=temp1->tlink)
                cout<<temp1->tailvex<<","<<temp1->cost<<"  ";
        }
        cout<<endl;
    }
}
//用邻接多重表存储,构造无向图G
AMLGraph CreateUDG_AML(AMLGraph &G,int c[N],int k)
{
    G.n=c[1];
    G.e=k;
    //cout<<G.e<<endl;
    for(int i=0; i<G.n; i++)
    {
        G.adjmulist[i].data=i;
        G.adjmulist[i].firstedge=NULL;
    }
    int sm=2;
    for(int j=0; j<G.e; j++)
    {
        int v1=c[sm];
        sm++;
        int v2=c[sm];
        sm++;
        int weight=c[sm];
        sm++;
        EBox *p=new EBox;
        p->ivex=v1;
        p->jvex=v2;
        p->cost=weight;
        p->ilink=G.adjmulist[v1].firstedge;
        p->jlink=G.adjmulist[v2].firstedge;
        G.adjmulist[v1].firstedge=p;
        G.adjmulist[v2].firstedge=p;
    }
    return G;
}
//输出无向图的多重链接表
void putAML(AMLGraph G)
{
    cout<<"无向图的多重链接表"<<endl;
    for(int i=0; i<G.n; i++)
    {
        cout<<G.adjmulist[i].data<<"  ";
        EBox *temp=G.adjmulist[i].firstedge;
        if(G.adjmulist[i].firstedge!=NULL)
        {
            while(temp!=NULL)
            {
                if(temp->ivex==i)
                {
                    cout<<temp->ivex<<" "<<temp->jvex<<" "<<temp->cost<<"  ";
                    temp=temp->ilink;
                }
                else
                {
                    cout<<temp->ivex<<" "<<temp->jvex<<" "<<temp->cost<<"  ";
                    temp=temp->jlink;
                }
            }
        }
        cout<<endl;
    }
}
//深度优先遍历
void DFS1(AdjGraph *G, int i) //以vi为出发点时对邻接表表示的图G进行先深搜索
{
    EdgeNode *p;
    cout<<G->vexlist[i].vertex<<"  "; //访问顶点vi;
    visit[i]=true;           //标记vi已访问
    //dfn[i]=count++;           //对vi进行编号
    p=G->vexlist[i].firstedge;  //取vi边表的头指针
    while(p)
    {
        //依次搜索vi的邻接点vj, 这里j=p->adjvex
        if(!visit[p->adjvex])   //若vj尚未访问
            DFS1(G,p->adjvex);   //则以vj为出发点先深搜索
        p=p->next;
    }
}
//广度优先遍历
void BFS2(MTGragh *G, int k)
{
    int j;
    queue <int> Q;
    cout << G->vertex[k]<<"  ";   //访问vk
    visit[k] = true; //给vk作访问过标记
    Q.push(k);   //vk进队列
    while (!Q.empty())
    {
        Q.pop();
        j=0;
        if (!visit[j])
        {
            cout<<G->vertex[j]<<"  ";
            visit[j]=true;  //给vj作访问过标记
            Q.push(j);  //访问过的vj入队
        }
        j++;
    }
}
//最小生成树普里姆(Prim)算法
void prim(MTGragh G)//begin作为初始顶点,n总的顶点数目
{
    cout<<"最小生成树为:"<<endl;
    int graph[N][N];
    for(int i=0; i<G.n; i++)
    {
        for(int j=0; j<G.n; j++)
        {
            graph[i][j]=FLAG;
            if(G.edge[i][j]!=0)
            {
                graph[i][j]=G.edge[i][j];
                graph[j][i]=G.edge[i][j];
            }
        }
    }
    int begin=0;
    int lowcost[N];
    int mst[N];
    for (int i = 0; i < G.n; i++) //初始化
    {
        if (i == begin)
            continue;
        lowcost[i] = graph[begin][i];//顶点1到其他定点的代价
        mst[i] = begin;//初始都指向顶点begin
    }
    mst[begin] = 0;//顶点begin在MST集合里
    lowcost[begin] = 0;
    for (int i = 0; i < G.n; i++)
    {
        if (i == begin)
            continue;
        int min = FLAG;
        int minid = 0;
        for (int j = 0; j < G.n; j++) //寻找lowcost中最小的边
        {
            if (j == begin)
                continue;
            if (lowcost[j] < min&&lowcost[j] != 0)
            {
                min = lowcost[j];
                minid = j;
            }
        }
        lowcost[minid] = 0;
        cout <<mst[minid] <<","<<minid <<"  "<< min << endl;//输出找到的最小一条边
        for (int j = 0; j < G.n; j++) //更新其他定点(主要变化的就是以minid为起始的边)
        {
            if (j == begin)
                continue;
            if (graph[minid][j] < lowcost[j])
            {
                lowcost[j] = graph[minid][j];
                mst[j] = minid;
            }
        }
    }
}
// Dijkstra 算法单源最短路径
void Dijkstra(MTGragh G)
{
    cout<<"Dijkstra 算法最短路径为:"<<endl;
    int D[G.n];
    int Path[G.n];
    bool S[G.n];
    int source=0;
    S[source] = true;
    int graph[G.n][G.n];
    for(int i=0; i<G.n; i++)
    {
        for(int j=0; j<G.n; j++)
        {
            graph[i][j]=FLAG;
            if(G.edge[i][j]!=0)
            {
                graph[i][j]=G.edge[i][j];
            }
            if(i==j)
                graph[i][j]=0;
        }
    }
    for (int i = 0; i < G.n; i++)
    {
        D[i] = graph[source][i];
        Path[i] = source;
    }
    int min_cost;        // 权值最小
    int min_cost_index;  // 权值最小的下标
    for (int i = 1; i < G.n; i++)
    {
        min_cost = FLAG;
        for (int j = 0; j < G.n; j++)
        {
            if (S[j] == false && D[j] < min_cost)  // 找到权值最小
            {
                min_cost = D[j];
                min_cost_index = j;
            }
        }
        D[min_cost_index] = true;  // 该点已找到,进行标记
        for (int j = 0; j < G.n; j++)  // 更新 dist 数组
        {// 确保两点之间有边
            if (S[j]==false&&graph[min_cost_index][j]!=INT_MAX&&graph[min_cost_index][j]+min_cost<D[j])
            {
                D[j] = graph[min_cost_index][j] + min_cost;
                Path[j] = min_cost_index;
            }
        }
    }
    for (int i = 0; i < G.n; i++)
    {
        if (i != source)
        {
            cout << source << "到" << i << "最短距离是:" << D[i] << ",路径是:" << i;
            int t = Path[i];
            while (t != source)
            {
                cout << "--" << t;
                t = Path[t];
            }
            cout << "--" << source << endl;
        }
    }
}
//有向图强连通分支的Korasaju算法
void Korasaju(OLGraph *G)
{
    cout<<"有向图强连通分支为:"<<endl;
    int  k=1, v, j ;
    for (v=0; v<G->n; v++)
        visit[v]=false ;
    for (v=0; v<G->n; v++)    //对图G正向遍历
        if (!visit[v])
            DFS(G,v) ;
    for (v=0; v<G->n; v++)
        visit[v]=false;
    for (j=G->n-1; j>=0; j--)
    {
        v=in_order[j] ;
        if (!visit[v])
        {
            cout<<k++<<"  ";
            Rev_DFS(G, v);    //对图G逆向遍历
            cout<<endl;
        }
    }
}
//拓扑排序算法
void Topologicalsort(AdjGraph G)
{
    cout<<"拓扑排序算法为:"<<endl;
    int i,j,k,top,m=0;
    EdgeNode *p;
    int d[G.n];
    for(i=0; i<G.n; i++)
        d[i]=0;
    for(i=0; i<G.n; i++)
    {
        p=G.vexlist[i].firstedge;
        while(p!=NULL)
        {
            j=p->adjvex;
            d[j]++;
            p=p->next;
        }
    }
    top=-1;
    for(i=0; i<G.n; i++)
    {
         if(d[i]==0)
        {
            d[i]=top;
            top=i;
        }
    }
    while(top!=-1)
    {
        j=top;
        top=d[top];
        cout<<j<<" ";
        m++;
        p=G.vexlist[j].firstedge;
        while(p!=NULL)
        {
            k=p->adjvex;
            d[k]--;
            if(d[k]==0)
            {
                d[k]=top;
                top=k;
            }
            p=p->next;
        }
    }
    if(m<G.n)
        cout<<"有回路"<<endl;
}


int main()
{
    ifstream infile;
    int data[N];
    infile.open("data.txt");
    int value;
    infile >> value;
    int sum=0;
    int i=0;
    while(infile.good())
    {
        sum++;
        data[i]=value;
        i++;
        infile >> value;
    }
    cout<<"所有的数据为:"<<endl;
    for(int i=0; i<sum; i++)
        cout<<data[i]<<" ";
    cout<<endl;
    cout<<endl;
    MTGragh G;
    int flag=data[0];
    int k=CreateMGragh(&G,data,flag,sum);
    putMgraph(G);
    cout<<endl;
    AdjGraph A;
    putGraph(CreateGraph(A,data,k));
    cout<<endl;
    OLGraph K;
    CreateDG(K,data,k);
    putDG(K);
    cout<<endl;
    AMLGraph AC=CreateUDG_AML(AC,data,k);
    putAML(AC);
    cout<<endl;
    // 先深搜索一邻接表表示的图G
    cout<<"深度优先遍历(DFS)结果为:"<<endl;
    AdjGraph SK = CreateGraph(SK,data,k);
    for ( int i = 0; i < SK.n; i++ )
        visit[i] =false;   //标志数组初始化
    for ( int i = 0; i < SK.n; i++ )
        if (!visit[i])
            DFS1(&SK,i); //从顶点 i 出发的一次搜索
    cout<<endl;
    cout<<endl;
    flag =1;
    MTGragh SB;
    CreateMGragh(&SB,data,flag,sum);
    cout<<"广度优先遍历(BFS)结果为:"<<endl;
    for(int i = 0; i < SB.n; i++ )
        visit[i]=false;   //标志数组初始化
    for(int i = 0; i < SB.n; i++ )
        if (!visit[i])
            BFS2(&SB,i); //从顶点 i 出发的一次搜索
    cout<<endl;
    cout<<endl;
    prim(G);
    cout<<endl;
    Dijkstra(G);
    cout<<endl;
    Korasaju(&K);
    cout<<endl;
    AdjGraph MM=CreateGraph(MM,data,k);
    Topologicalsort(MM);
    return 0;
}
void  DFS(OLGraph *G, int v)
{
    ArcBox *p;
    visit[v]=true ;
    for(p=G->xlist[v].firstout ; p!=NULL ; p=p->tlink)
        if(!visit[p->tailvex])
            DFS(G,p->tailvex);
    in_order[count++]=v;
}
void  Rev_DFS(OLGraph *G, int v)
{
    ArcBox *p ;
    visit[v]=true;
    cout<<v<<"  ";
    for(p=G->xlist[v].firstin ; p!=NULL ; p=p->hlink)
        if(!visit[p->headvex])
            Rev_DFS(G,p->headvex);
    //cout<<endl;
}

猜你喜欢

转载自blog.csdn.net/qq_36719861/article/details/78699250