图:图是一种数据结构,由顶点的有穷非空集合和顶点之间边的集合组成,表示为G(V,E),V表示为顶点的集
合,E表示为边的集合。
首先肯定是要对图进行存储,然后进行一系列的操作,下面对图的两种存储方式邻接矩阵和邻接表尽行介绍。
(一)、邻接矩阵存储:
用两个数组分别进行存储数据元素(顶点)的信息和数据元素之间的关系(边或弧)的信息。
存储顶点:用一个连续的空间存储n个顶点。
存储顶点之间的边:将由n个顶点组成的边用一个n*n的矩阵来存储,如果两个顶点之间有边,则表示为1,否
则表示为0。
下面用代码来实现邻接矩阵的存储:
#define SIZE 10 class Graph { public: Graph() { MaxVertices = SIZE; NumVertices = NumEdges = 0; VerticesList = new char[sizeof(char)*MaxVertices]; Edge = new int*[sizeof(int*)*MaxVertices]; int i,j; for(i = 0;i<MaxVertices;i++) Edge[i] = new int[sizeof(int)*MaxVertices]; for(i = 0;i<MaxVertices;i++) { for(j = 0;j<MaxVertices;++j) Edge[i][j] = 0; } } void ShowGraph() { int i,j; cout<<" "; for(i = 0;i<NumVertices;i++) cout<<VerticesList[i]<<" "; cout<<endl; for(i = 0;i<NumVertices;i++) { cout<<VerticesList[i]<<" "; for(j = 0;j<NumVertices;j++) cout<<Edge[i][j] <<" "; cout<<endl; } cout<<endl; } int GetVertexPos(char v) { int i; for(i = 0;i<NumVertices;i++) { if(VerticesList[i] == v) return i; } return -1; } ~Graph() { Destroy(); } void Insert(char v) { if(NumVertices < MaxVertices) { VerticesList[NumVertices] = v; NumVertices++; } } void InsertEdge(char v1,char v2) { int i,j; int p1 = GetVertexPos(v1); int p2 = GetVertexPos(v2); if(p1 == -1 || p2 == -1) return ; Edge[p1][p2] = Edge[p2][p1] = 1; NumEdges++; } void RemoveEdge(char v1,char v2) { int p1 = GetVertexPos(v1); int p2 = GetVertexPos(v2); if(p1 == -1 || p2== -1) return; if(Edge[p1][p2] == 0) return; Edge[p1][p2] = Edge[p2][p1] = 0; NumEdges--; } void Destroy() { delete[] VerticesList; VerticesList = NULL; for(int i = 0;i<NumVertices;i++) { delete Edge[i]; Edge[i] = NULL; } delete[] Edge; Edge = NULL; MaxVertices = NumVertices = 0; } void RemoveVertex(char v) { int i,j; int p = GetVertexPos(v); int reNum = 0; if(p == -1) return; for(i = p;i<NumVertices-1;i++) { VerticesList[i] = VerticesList[i+1]; } for(i = 0;i<NumVertices;i++) { if(Edge[p][i] != 0) reNum++; } for(i = p;i<NumVertices-1;i++) { for(j = 0;j<NumVertices;j++) { Edge[i][j] = Edge[i+1][j]; } } for(i = p;i<NumVertices;i++) { for(j = 0;j<NumVertices;j++) Edge[j][i] = Edge[j][i+1]; } NumVertices--; NumEdges = NumEdges - reNum; } private: int MaxVertices; int NumVertices; int NumEdges; char *VerticesList; int **Edge; };
上面的类中的数据有定义最大的顶点的个数(MaxVertices),当前顶点的个数(NumVertices),当前边的个数
(NumEdges),保存顶点的数组,保存边的数组。其中的方法是(1)构造函数:对定义的数据进行初始化。(2)显
示构造的图的信息的函数。(3)得到顶点位置信息的函数。(4)析构函数:调用销毁函数。(5)插入顶点函数。
(6)插入边的函数。(7)删除边的函数。(8)销毁函数,释放开辟的内存空间。(9)删除顶点函数。
(二)、邻接表存储:
邻接表是图的一种链式存储结构。用数组存储顶点,用链表存储和顶点相关联的边,边值为当前顶点在数组中的下
标。用如下图可以表示邻接表的存储方式:
下面用代码来实现邻接表的存储:
#define SIZE 10 typedef char T; struct Edge { Edge(int v):destvalue(v),link(NULL){} int destvalue; Edge *link; }; struct Vertex { Vertex():list(NULL){} T data; Edge *list; }; class GraphLnk { public: GraphLnk(); ~GraphLnk(){} void InsertVertex(T v); void InsertEdge(T v1,T v2); int GetVertexI(T v); void ShowGraph(); void RemoveEdge(T v1,T v2); void RemoveVertex(T v); void DestroyGraph(); private: int MaxVertex; int NumVertex; int NumEdge; Vertex *VertexTable; }; GraphLnk::GraphLnk() { MaxVertex = SIZE; NumVertex = NumEdge = 0; VertexTable = new Vertex[MaxVertex]; } void GraphLnk::InsertVertex(T v) { if(NumVertex >= MaxVertex) return; VertexTable[NumVertex++].data = v; } void GraphLnk::ShowGraph() { int i; for(i = 0;i<NumVertex;i++) { cout<<i<<" "<<VertexTable[i].data<<":->"; Edge *p = VertexTable[i].list; while(p != NULL) { cout<<p->destvalue<<"->"; p = p->link; } cout<<"nul"<<endl; } cout<<endl; } int GraphLnk::GetVertexI(T v) { int i; for(i = 0;i<NumVertex;i++) { if(VertexTable[i].data == v) return i; } return -1; } void GraphLnk::InsertEdge(T v1,T v2) { int p1 = GetVertexI(v1); int p2 = GetVertexI(v2); if(p1 == -1 || p2 == -1) return; //v1 -> v2 Edge *ed = new Edge(p2); ed->link = VertexTable[p1].list; VertexTable[p1].list = ed; //v2 -> v1 ed = new Edge(p1); ed->link = VertexTable[p2].list; VertexTable[p2].list = ed; NumEdge++; } void GraphLnk::RemoveEdge(T v1,T v2) { int p1 = GetVertexI(v1); int p2 = GetVertexI(v2); if(p1 == -1 || p2 == -1) return; Edge *q = NULL; //标识要删除边链表的前一个 Edge *p; p = VertexTable[p1].list; //从链表开头开始 //查找v2所在位置 while(p != NULL && p->destvalue != p2) { q = p; p = p->link; } if(p == NULL) //两个顶点之间没有边的存在¨ return; //找到所要删除的边 if(q == NULL) //所要删除的为链表开头 { VertexTable[p1].list = p->link; } else { q->link = p->link; } delete p; p = NULL; q = NULL; p = VertexTable[p2].list; while(p->destvalue != p1) { q = p; p = p->link; } if(q == NULL) { VertexTable[p2].list = p->link; } else { q->link = p->link; } delete p; p = NULL; NumEdge--; } void GraphLnk::RemoveVertex(T vertex) { int v = GetVertexI(vertex); if(v == -1) return; //删除和结点相关的边 Edge*p=VertexTable[v].list; Edge *s; Edge *t = NULL; int k; while(p != NULL) { k = p->destvalue; s = VertexTable[k].list; while(s != NULL&&s->destvalue != v) { t = s; s = s->link; } if(s != NULL) { if(t == NULL) //第一个结点 { VertexTable[k].list = s->link; } else { t->link = s->link; } delete s; s = NULL; } VertexTable[v].list = p->link; delete p; p = VertexTable[v].list; } /*删除结点,用最后一个结点覆盖要删除的结点,并把和 最后一个结点相关联的边的下标改正 */ NumVertex--; VertexTable[v].data = VertexTable[NumVertex].data; VertexTable[v].list = VertexTable[NumVertex].list; s = VertexTable[v].list; while(s != NULL) { k = s->destvalue; p = VertexTable[k].list; while(p != NULL) { if(p->destvalue == NumVertex) { p->destvalue = v; break; } p = p->link; } s = s->link; } } void GraphLnk::DestroyGraph() { Edge *p; for(int i = 0;i<NumVertex;i++) { p = VertexTable[i].list; while(p != NULL) { VertexTable[i].list = p->link; delete p; p = VertexTable[i].list; } } delete []VertexTable; MaxVertex = NumEdge = NumVertex = 0; }
在代码实现的过程中,先定义出顶点和边的数据结构,然后在类中定义了最大顶点数,当前顶点的个数,当前的
边的个数,顶点类型的数组,还有在类中进行了函数的声明,包括(1)构造函数。(2)析构函数。(3)插入顶点
函数。(4)插入边函数。(5)得到顶点位置的函数。(6)显示构造出的图的信息函数。(7)删除边函数。(8)
删除顶点函数。(9)销毁函数。