构建一个图

在练习图的各种算法时,比如深度优先搜索,拓扑排序,最短路径,最小生成树等等,都希望得到有效的验证,这就必须先自己构建出图的存储结构。才能将图实例信息用于算法验证。

要完整的构建一个图比较复杂,这里只是给出一个非常简单的例子,讲述如何使用邻接表构建一个图。基本是C语言实现。

 

     

    此例,我们认为v1-v7的位置信息为 1-7,即v1位置为1,v2位置为2,。。。

    于是,我们能得到邻接表为:

         v1 -> 2, 3, 4
         v2 -> 4, 5
         v3 -> 6  
         v4 -> 6, 7, 3
         v5 -> 4, 7
         v6 -> NULL
         v7 -> 6
   
 也就是说,如果我们更改每个结点的data信息,邻接表只会变化左侧的顶点信息,而右侧的链表信息不会变。
 

     仍然是利用之前介绍过得三个结构体:
         #define MAX_VERTEX_NUM    20
        struct adjVertexNode
        {
            int adjVertexPosition;
            adjVertexNode * next;
        }
        struct VertexNode
        {
            char * data; //以结点存储的信息为字符为例。
            adjVertexNode * list; //邻接点链表。
            int indegree;
        }
        struct Graph
        {
            VertexNode VertexNode [ MAX_VERTEX_NUM ];
            int vertexNum;
        }

    首先,必须有个图实例,以及其基本信息。     
        Graph g;
        g.vertexnum = 7;   //7个顶点。
    然后,为图添加顶点信息, 由邻接表信息可知一定需要一个顶点数组,一个邻接链表头数组
        VertexNode v[7];
        adjVertexNode* adjList[7] = {NULL};
        以邻接表信息 v1 -> v2, v3, v4 为例,他其实代表的位置信息为: 1 -> 2, 3, 4
        //顶点信息
        v[0].data = "v1";
        v[0].indegree = 0;
        v[0].list = adjList[0];
        //邻接链表信息
        adjList[0] = new adjVertexNode();
        adjList[0]->adjVertexPosition = 1; //v2对应的位置2,但考虑到数组以0起始,所以应为1,即“v[1]”中的1.
        adjList[0]->next = new adjVertexNode();
        adjList[0]->next->adjVertexPosition = 2; // v3对应的位置信息
        adjList[0]->next->next = new adjVertexNode();
        adjList[0]->next->next->adjVertexPosition = 3; // v4对应的位置信息
        adjList[0]->next->next->next = NULL;
        这里有点绕,务必看清楚,小结也下,v1 -> 2, 3, 4 开头说了这里的2,3,4为图中顶点 v2, v3, v4的位置信息。
        但在程序中v2, v3, v4 的位置信息为1,2,3,因为数组是从0开始的。所以v[1] 代表v2,即v2在程序中存储的位置信息为1.
        同理添加v2-v7顶点的信息。
    最后, 将顶点信息赋值给图实例即可。
        for (int i=0; i<7; i++)
        {
            g.VertexNode[i] = v[i];
        }
     代码实现:
#include <iostream>
using namespace std;

#define MAX_VERTEX_NUM    20
struct adjVertexNode
{
    int adjVertexPosition;
    adjVertexNode * next;
};
struct VertexNode
{
    char * data; //以结点存储的信息为字符为例。
    adjVertexNode * list; //邻接点链表。
    int indegree;
};
struct Graph
{
    VertexNode VertexNode [ MAX_VERTEX_NUM ];
    int vertexNum;
};

void PrintAdjList( Graph & g)
{
    for ( int i = 0; i < g . vertexNum; i ++)
    {
        cout << g . VertexNode [ i ]. data << "->";
        adjVertexNode * head = g . VertexNode [ i ]. list;
        if ( head == NULL)
            cout << "NULL";
        while ( head != NULL)
        {
            cout << head -> adjVertexPosition + 1 << " ";
            head = head -> next;
        }
        cout << endl;
    }
}
int main( int argc , const char ** argv)
{
    Graph g;
    g . vertexNum = 7;
    VertexNode v [ 7 ];
    adjVertexNode * adjList [ 7 ] = { NULL };

    // v1 -> v2, v3, v4
    adjList [ 0 ] = new adjVertexNode();
    adjList [ 0 ] -> adjVertexPosition = 1;
    adjList [ 0 ] -> next = new adjVertexNode();
    adjList [ 0 ] -> next -> adjVertexPosition = 2;
    adjList [ 0 ] -> next -> next = new adjVertexNode();
    adjList [ 0 ] -> next -> next -> adjVertexPosition = 3;
    adjList [ 0 ] -> next -> next -> next = NULL;
    v [ 0 ]. data = "v1";
    v [ 0 ]. indegree = 0;
    v [ 0 ]. list = adjList [ 0 ];
    // v2-> v4, v5
    adjList [ 1 ] = new adjVertexNode();
    adjList [ 1 ] -> adjVertexPosition = 3;
    adjList [ 1 ] -> next = new adjVertexNode();
    adjList [ 1 ] -> next -> adjVertexPosition = 4;
    adjList [ 1 ] -> next -> next = NULL;
    v [ 1 ]. data = "v2";
    v [ 1 ]. indegree = 1;
    v [ 1 ]. list = adjList [ 1 ];
    // v3-> v6
    adjList [ 2 ] = new adjVertexNode();
    adjList [ 2 ] -> adjVertexPosition = 5;
    adjList [ 2 ] -> next = NULL;
    v [ 2 ]. data = "v3";
    v [ 2 ]. indegree = 2;
    v [ 2 ]. list = adjList [ 2 ];
    // v4-> v6, v7, v3
    adjList [ 3 ] = new adjVertexNode();
    adjList [ 3 ] -> adjVertexPosition = 5; //6
    adjList [ 3 ] -> next = new adjVertexNode();
    adjList [ 3 ] -> next -> adjVertexPosition = 6;
    adjList [ 3 ] -> next -> next = new adjVertexNode();
    adjList [ 3 ] -> next -> next -> adjVertexPosition = 2;
    adjList [ 3 ] -> next -> next -> next = NULL;
    v [ 3 ]. data = "v4";
    v [ 3 ]. indegree = 3;
    v [ 3 ]. list = adjList [ 3 ];
    // v5-> v4, v7
    adjList [ 4 ] = new adjVertexNode();
    adjList [ 4 ] -> adjVertexPosition = 3;
    adjList [ 4 ] -> next = new adjVertexNode();
    adjList [ 4 ] -> next -> adjVertexPosition = 6;
    adjList [ 4 ] -> next -> next = NULL;
    v [ 4 ]. data = "v5";
    v [ 4 ]. indegree = 1;
    v [ 4 ]. list = adjList [ 4 ];
    // v6-> NULL
    v [ 5 ]. data = "v6";
    v [ 5 ]. indegree = 3;
    v [ 5 ]. list = adjList [ 5 ]; //NULL
    // v7-> v6
    adjList [ 6 ] = new adjVertexNode();
    adjList [ 6 ] -> adjVertexPosition = 5;
    adjList [ 6 ] -> next = NULL;
    v [ 6 ]. data = "v7";
    v [ 6 ]. indegree = 2;
    v [ 6 ]. list = adjList [ 6 ];
   
    for ( int i = 0; i < 7; i ++)
    {
        g . VertexNode [ i ] = v [ i ];
    }

    PrintAdjList( g);

    //delete graph: delete adjcent lists
    for ( int i = 0; i < 7; i ++)
    {
        adjVertexNode * tmp = NULL;
        while( adjList [ i ] != NULL)
        {
            tmp = adjList [ i ];
            adjList [ i ] = adjList [ i ] -> next;
            delete tmp;
            tmp = NULL;
        }
    }
}

     

    这个例子,你应该能看出很多问题,比如链表信息,完全是自己添加的,不是自动生成的,顶点个数是hard code,等等,这里写这样一段代码的主要目的是明确邻接表是如何存储一个图结构的。

     下面这段代码,实现了一般图结构的邻接表构建方式,即:需要输入的是顶点信息,边信息。最后可以打印出邻接表。

 

#include <iostream>
using namespace std;

#define MAX_VERTEX_NUM    20
struct adjVertexNode
{
    int adjVertexPosition;
    adjVertexNode * next;
};
struct VertexNode
{
    char data [ 2 ];
    adjVertexNode * list;
    //int indegree;
};
struct Graph
{
    VertexNode VertexNode [ MAX_VERTEX_NUM ];
    int vertexNum;
    int edgeNum;
};

void CreateGraph ( Graph & g)
{
     int i , j , edgeStart , edgeEnd;
     adjVertexNode * adjNode;
     cout << "Please input vertex and edge num (vnum enum):" << endl;
     cin >> g . vertexNum >> g . edgeNum;
     cout << "Please input vertex information (v1) /n note: every vertex info end with Enter" << endl;
     for ( i = 0; i < g . vertexNum; i ++)
     {
         cin >> g . VertexNode [ i ]. data; // vertex data info.
         g . VertexNode [ i ]. list = NULL;
     }
     cout << "input edge information(start end):" << endl;
     //每多一条边,就会多一个邻接点
     for ( j = 0; j < g . edgeNum; j ++)
     {
         cin >> edgeStart >> edgeEnd;
         adjNode = new adjVertexNode;
         adjNode -> adjVertexPosition = edgeEnd - 1; // because array begin from 0, so it is j-1
         // 将邻接点信息插入到顶点Vi的邻接表头部,注意是头部!!!不是尾部。
         adjNode -> next = g . VertexNode [ edgeStart - 1 ]. list;
         g . VertexNode [ edgeStart - 1 ]. list = adjNode;
     }
}

void PrintAdjList( const Graph & g)
{
    for ( int i = 0; i < g . vertexNum; i ++)
    {
        cout << g . VertexNode [ i ]. data << "->";
        adjVertexNode * head = g . VertexNode [ i ]. list;
        if ( head == NULL)
            cout << "NULL";
        while ( head != NULL)
        {
            cout << head -> adjVertexPosition + 1 << " ";
            head = head -> next;
        }
        cout << endl;
    }
}
void DeleteGraph( Graph & g)
{
    for ( int i = 0; i < g . vertexNum; i ++)
    {
        adjVertexNode * tmp = NULL;
        while( g . VertexNode [ i ]. list != NULL)
        {
            tmp = g . VertexNode [ i ]. list;
            g . VertexNode [ i ]. list = g . VertexNode [ i ]. list -> next;
            delete tmp;
            tmp = NULL;
        }
    }
}
int main( int argc , const char ** argv)
{
    Graph g;
    CreateGraph( g);
    PrintAdjList( g);
    DeleteGraph( g);
    return 0;
}

    运行结果:

       

     当然,对于图结构有更为详细的实现方式,比如使用模板,类的方式实现 http://www.ut365.com/shujujiegou/225.html  相对复杂些。
    
                  C代码      http://bbs.pfan.cn/post-216439.html

 

    

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值