圖:圖是一種數據結構,由頂點的有窮非空集合和頂點之間邊的集合組成,表示為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)銷毀函數。