adjacency list
basic concept
When the graph is sparse and represented by an adjacency matrix, the utilization rate of the adjacency matrix is too low, resulting in a certain waste of resources. The adjacency list is a chain storage structure proposed to save the storage space of the graph. In this chain structure, a singly linked list is established for each vertex Vertex in the graph. In this singly linked list, each node consists of three chain domains: adjvex adjacency point, nextarc pointing to the next edge, and information info corresponding to the edge. As shown below:
In addition, in order to represent all the vertices in the graph, a structure array AdjList[num] is used in the adjacency list structure. The array element is a structure with two chain fields (the vertex information and the corresponding first arc for that vertex). It is as follows:
As shown in the following undirected graph, there are 4 vertices V={v1, v2, v3, v4}, 4 edges E={(v1, v2), (v1, v3), (v3, v4), (v4, v1)}.
When the above graph is represented by an adjacency list, as shown in the following figure:
As can be seen from the above figure, the singly linked list 1 represents 3 arcs connected to the first vertex v1, and the first link field in each node in the linked list represents the other vertices adjacent to the node at the vertex position in the array. Connected to the first vertex v1 are vertex 2, vertex 3 and vertex 4, so the first link domains of the three nodes in the linked list are 3, 2 and 1 respectively. Others follow and so on. Also, note that adjacency lists represent some of the differences between directed and undirected graphs.
Basic operation
Status createGraph(ALGraph &G, string kind, int vertexNum, int arcNum){ //Construct a graph using an adjacency list (directed or undirected) G.kind = kind; G.vertexNum = vertexNum; G.arcNum = arcNum; //Initialize vertex information 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);//Insert arc } 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; }
Status insertArc(ALGraph &G, VertexNode node1, VertexNode node2){ int nodeNum1 = locateNode(G, node1);//i and j represent the position in AdjList[MAX_VERTEX_NUM] int nodeNum2 = locateNode(G, node2); if(nodeNum1<0 || nodeNum2<0) exit(-1); if(G.kind == "DG")//Directed graph, insert once insertArcAction(G, nodeNum1, nodeNum2); else{//The undirected graph is inserted twice 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;//Equivalent to the insertion of a linked list if(!p){ G.vertices[nodeNum1].firstArc = arc; arc->nextArc = NULL; } else{ G.vertices[nodeNum1].firstArc = arc; arc->nextArc = p; } }
Status deleteArc(ALGraph &G, VertexNode node1, VertexNode node2){ //node1 is the arc tail, node2 is the arc head: node1 ----> node2 int index1 = locateNode(G, node1); int index2 = locateNode(G, node2); if(index1 < 0 || index2 < 0) exit(-1); if(G.kind == "DG"){ //Delete arc from directed graph, delete once deleteArcAction(G, index1, index2); } else{ //Undirected graph delete arc, delete twice 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;//The node has no corresponding arc else if(count <=1) G.vertices[index1].firstArc = pre->nextArc; else pre->nextArc = cur->nextArc; }
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);//Delete the arc corresponding to this node as the arc head } } G.vertices[index].firstArc = NULL;//Delete all arcs from this node G.vertices[index].data = INT_FIN;//Use a large number to indicate that the node is deleted return 1; }
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; }
#include "stdafx.h" #include <iostream> #include <string> #define MAX_VERTEX_NUM 20 #define INT_FIN 500 using namespace std; typedef int infoType;//Arc info typedef char vertexType;//Vertex save character information 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){ //Construct a graph using an adjacency list (directed or undirected) G.kind = kind; G.vertexNum = vertexNum; G.arcNum = arcNum; //Initialize vertex information 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;//Equivalent to the insertion of a linked list 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 and j represent the position in 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);//Delete the arc corresponding to this node as the arc head } } G.vertices[index].firstArc = NULL;//Delete all arcs from this node G.vertices[index].data = INT_FIN;//Use a large number to indicate that the node is deleted 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;//The node has no corresponding arc else if(count <=1) G.vertices[index1].firstArc = pre->nextArc; else pre->nextArc = cur->nextArc; } Status deleteArc(ALGraph &G, VertexNode node1, VertexNode node2){ //node1 is the arc tail, node2 is the arc head: node1 ----> node2 int index1 = locateNode(G, node1); int index2 = locateNode(G, node2); if(index1 < 0 || index2 < 0) exit(-1); if(G.kind == "DG"){ //Delete arc from directed graph, delete once deleteArcAction(G, index1, index2); } else{ //Undirected graph delete arc, delete twice 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; }