邻接表
基本概念
当图比较稀疏并且用邻接矩阵表示时,邻接矩阵的利用率太低,造成一定的资源浪费。邻接表就是为了节省图的存储空间而提出来的一种链式存储结构。该链式结构中,为图中的每一个顶点Vertex建立一个单链表。在该单链表中,各个结点由3个链域组成:adjvex邻接点、指向下一个边的nextarc和该边对应的信息info。如下图所示:
另外,为了表示图中的所有的顶点,邻接表结构中采用了一个结构体数组AdjList[num]。数组元素是一个有两个链域(顶点信息和该顶点的对应的第一条弧)的结构体。其具体如下所示:
如下面的无向图,共4个顶点V={v1,v2,v3,v4},4条边E={(v1,v2),(v1,v3),(v3,v4),(v4,v1)}。
当用邻接表表示上图时,如下图所示:
从上图可以看出,单链表1 表示与第一个顶点v1相连的3条弧,其中链表中的各个结点中的第一个链域表示与该结点相邻接的其他顶点在顶点数组中的位置。与第一个顶点v1相连的分别是顶点2,顶点3和顶点4,因此该链表中的三个结点的第一个链域分别为3,2和1。其他依次类推。另外,需要注意的是,邻接表表示有向图和无向图的一些区别。
基本操作
1、构造图的邻接表
Status createGraph(ALGraph &G, string kind, int vertexNum, int arcNum){
//采用邻接表构造图(有向或无向图)
G.kind = kind;
G.vertexNum = vertexNum;
G.arcNum = arcNum;
//初始化顶点信息
for(int i = 0; i<G.vertexNum; i++){
cin>>G.vertices[i].data;
G.vertices[i].firstArc = NULL;
}
cout<<"Try to input arcs info"<<endl;
for(int j = 0; j<G.arcNum; j++){
cout<<"please input two nodes of "<<j+1<<"-th arc"<<endl;
VertexNode node1, node2;
cin>>node1.data>>node2.data;
insertArc(G, node1, node2);//插入弧
}
return 1;
}
2、打印邻接图
Status printALGraph(ALGraph &G){
for(int i = 0; i<G.vertexNum; i++){
cout<<i<<" "<<G.vertices[i].data;
ArcNode *arc = G.vertices[i].firstArc;
while(arc){
cout<<"-->"<<arc->adjvex;
arc = arc->nextArc;
}
cout<<"-->NULL"<<endl;
}
return 1;
}
3、两个顶点之间插入弧
Status insertArc(ALGraph &G, VertexNode node1, VertexNode node2){
int nodeNum1 = locateNode(G, node1);//i和j表示AdjList[MAX_VERTEX_NUM]中的位置
int nodeNum2 = locateNode(G, node2);
if(nodeNum1<0 || nodeNum2<0) exit(-1);
if(G.kind == "DG")//有向图,插入一次
insertArcAction(G, nodeNum1, nodeNum2);
else{//无向图插入两次
insertArcAction(G, nodeNum1, nodeNum2);
insertArcAction(G, nodeNum2, nodeNum1);
}
return 1;
}
void insertArcAction(ALGraph &G, int nodeNum1, int nodeNum2){
ArcNode *p;
ArcNode *arc;
arc = new ArcNode[1];
arc->adjvex = nodeNum2;
p = G.vertices[nodeNum1].firstArc;//相当于链表的插入
if(!p){
G.vertices[nodeNum1].firstArc = arc;
arc->nextArc = NULL;
}
else{
G.vertices[nodeNum1].firstArc = arc;
arc->nextArc = p;
}
}
4、删除弧
Status deleteArc(ALGraph &G, VertexNode node1, VertexNode node2){
//node1为弧尾,node2为弧头:node1 ----> node2
int index1 = locateNode(G, node1);
int index2 = locateNode(G, node2);
if(index1 < 0 || index2 < 0) exit(-1);
if(G.kind == "DG"){
//有向图删除弧,删除一次
deleteArcAction(G, index1, index2);
}
else{
//无向图删除弧,删除两次
deleteArcAction(G, index1, index2);
deleteArcAction(G, index2, index1);
}
return 1;
}
void deleteArcAction(ALGraph &G, int index1, int index2){
ArcNode *cur = G.vertices[index1].firstArc;
ArcNode *pre = cur;
int count = 0;
if(!cur)
return;
else{
while(cur){
count++;
if(cur->adjvex == index2)
break;
pre = cur;
cur = cur->nextArc;
}
}
if(!cur)
return;//该结点没有对应的弧
else if(count <=1)
G.vertices[index1].firstArc = pre->nextArc;
else
pre->nextArc = cur->nextArc;
}
5、删除顶点
Status deleteVertex(ALGraph &G, VertexNode node){
int index = locateNode(G, node);
for(int i = 0; i<G.vertexNum; i++){
if(i == index)
continue;
else{
VertexNode node1 = G.vertices[i];
deleteArc(G, node1, node);//删除以该结点为弧头对应的弧
}
}
G.vertices[index].firstArc = NULL;//删除所有该结点出发的弧
G.vertices[index].data = INT_FIN;//用一个很大的数表示该结点被删除
return 1;
}
6、定位顶点
int locateNode(ALGraph &G, VertexNode node){
for(int i=0; i<G.vertexNum;i++){
if(node.data == G.vertices[i].data)
return i;
}
return -1;
}
7、全部代码
#include "stdafx.h"
#include <iostream>
#include <string>
#define MAX_VERTEX_NUM 20
#define INT_FIN 500
using namespace std;
typedef int infoType;//弧信息
typedef char vertexType;//顶点保存字符信息
typedef int Status;
typedef struct ArcNode{
int adjvex;
struct ArcNode *nextArc;
infoType *info;
}ArcNode;
typedef struct VertexNode{
vertexType data;
ArcNode *firstArc;
}VertexNode, AdjList[MAX_VERTEX_NUM];
typedef struct ALGraph{
AdjList vertices;
int vertexNum, arcNum;
string kind;
}ALGraph;
int locateNode(ALGraph &G, VertexNode node){
for(int i=0; i<G.vertexNum;i++){
if(node.data == G.vertices[i].data)
return i;
}
return -1;
}
void insertArcAction(ALGraph &G, int nodeNum1, int nodeNum2);
Status insertArc(ALGraph &G, VertexNode node1, VertexNode node2);
Status createGraph(ALGraph &G, string kind, int vertexNum, int arcNum){
//采用邻接表构造图(有向或无向图)
G.kind = kind;
G.vertexNum = vertexNum;
G.arcNum = arcNum;
//初始化顶点信息
for(int i = 0; i<G.vertexNum; i++){
cin>>G.vertices[i].data;
G.vertices[i].firstArc = NULL;
}
cout<<"Try to input arcs info"<<endl;
for(int j = 0; j<G.arcNum; j++){
cout<<"please input two nodes of "<<j+1<<"-th arc"<<endl;
VertexNode node1, node2;
cin>>node1.data>>node2.data;
insertArc(G, node1, node2);
}
return 1;
}
Status insertVertex(ALGraph &G, VertexNode node){
G.vertexNum = G.vertexNum + 1;
G.vertices[G.vertexNum - 1].data = node.data;
G.vertices[G.vertexNum - 1].firstArc = NULL;
return 1;
}
void insertArcAction(ALGraph &G, int nodeNum1, int nodeNum2){
ArcNode *p;
ArcNode *arc;
arc = new ArcNode[1];
arc->adjvex = nodeNum2;
p = G.vertices[nodeNum1].firstArc;//相当于链表的插入
if(!p){
G.vertices[nodeNum1].firstArc = arc;
arc->nextArc = NULL;
}
else{
G.vertices[nodeNum1].firstArc = arc;
arc->nextArc = p;
}
}
Status insertArc(ALGraph &G, VertexNode node1, VertexNode node2){
int nodeNum1 = locateNode(G, node1);//i和j表示AdjList[MAX_VERTEX_NUM]中的位置
int nodeNum2 = locateNode(G, node2);
if(nodeNum1<0 || nodeNum2<0) exit(-1);
if(G.kind == "DG")
insertArcAction(G, nodeNum1, nodeNum2);
else{
insertArcAction(G, nodeNum1, nodeNum2);
insertArcAction(G, nodeNum2, nodeNum1);
}
return 1;
}
Status printALGraph(ALGraph &G){
for(int i = 0; i<G.vertexNum; i++){
cout<<i<<" "<<G.vertices[i].data;
ArcNode *arc = G.vertices[i].firstArc;
while(arc){
cout<<"-->"<<arc->adjvex;
arc = arc->nextArc;
}
cout<<"-->NULL"<<endl;
}
return 1;
}
void deleteArcAction(ALGraph &G, int index1, int index2);
Status deleteArc(ALGraph &G, VertexNode node1, VertexNode node2);
Status deleteVertex(ALGraph &G, VertexNode node){
int index = locateNode(G, node);
for(int i = 0; i<G.vertexNum; i++){
if(i == index)
continue;
else{
VertexNode node1 = G.vertices[i];
deleteArc(G, node1, node);//删除以该结点为弧头对应的弧
}
}
G.vertices[index].firstArc = NULL;//删除所有该结点出发的弧
G.vertices[index].data = INT_FIN;//用一个很大的数表示该结点被删除
return 1;
}
void deleteArcAction(ALGraph &G, int index1, int index2){
ArcNode *cur = G.vertices[index1].firstArc;
ArcNode *pre = cur;
int count = 0;
if(!cur)
return;
else{
while(cur){
count++;
if(cur->adjvex == index2)
break;
pre = cur;
cur = cur->nextArc;
}
}
if(!cur)
return;//该结点没有对应的弧
else if(count <=1)
G.vertices[index1].firstArc = pre->nextArc;
else
pre->nextArc = cur->nextArc;
}
Status deleteArc(ALGraph &G, VertexNode node1, VertexNode node2){
//node1为弧尾,node2为弧头:node1 ----> node2
int index1 = locateNode(G, node1);
int index2 = locateNode(G, node2);
if(index1 < 0 || index2 < 0) exit(-1);
if(G.kind == "DG"){
//有向图删除弧,删除一次
deleteArcAction(G, index1, index2);
}
else{
//无向图删除弧,删除两次
deleteArcAction(G, index1, index2);
deleteArcAction(G, index2, index1);
}
return 1;
}
int _tmain(int argc, _TCHAR* argv[])
{
ALGraph G;
string kind = "UDG";
int vertexNum = 4;
int arcNum = 4;
cout<<"Try to create a Adjacency list Graph ..."<<endl;
createGraph(G, kind, vertexNum, arcNum);
cout<<"Try to print a Adjacence list Graph ..."<<endl;
printALGraph(G);
cout<<"Try to insert two nodes into a Adjacence list Graph ..."<<endl;
VertexNode node1;
node1.data = 'E';
insertVertex(G, node1);
VertexNode node2;
node2.data = 'F';
insertVertex(G, node2);
printALGraph(G);
cout<<"Try to insert a arc into a Adjacence list Graph ..."<<endl;
insertArc(G, node1, node2);
printALGraph(G);
cout<<"Try to delete a arc of a Adjacence list Graph ..."<<endl;
VertexNode node3;
node3.data = 'A';
VertexNode node4;
node4.data = 'D';
deleteArc(G, node3, node4);
printALGraph(G);
cout<<"Try to delete a node of a Adjacence list Graph ..."<<endl;
deleteVertex(G,node3);
printALGraph(G);
system("pause");
return 0;
}
8、测试结果