在练习图的各种算法时,比如深度优先搜索,拓扑排序,最短路径,最小生成树等等,都希望得到有效的验证,这就必须先自己构建出图的存储结构。才能将图实例信息用于算法验证。
要完整的构建一个图比较复杂,这里只是给出一个非常简单的例子,讲述如何使用邻接表构建一个图。基本是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信息,邻接表只会变化左侧的顶点信息,而右侧的链表信息不会变。
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;
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,等等,这里写这样一段代码的主要目的是明确邻接表是如何存储一个图结构的。
下面这段代码,实现了一般图结构的邻接表构建方式,即:需要输入的是顶点信息,边信息。最后可以打印出邻接表。
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;
}
运行结果: