由於圖的基本操作的代碼較多,我放到這一章來寫。圖可以用兩種方法來存儲,但是本人偏愛鏈表的表示方法,所以以下代碼也都是是基於鄰接鏈表的存儲方式。
1 /* 2 以下存儲結構參考嚴蔚敏版數據結構,不懂的可以翻閱查看 3 */ 4 const int UNDIGRAPH = 0; //無向圖 5 const int DIGRAPH = 1; //有向圖 6 const int MAX_VERTEX_NUM = 20; 7 8 typedef struct ArchNode 9 { 10 int vertexIndex; //該弧指向頂點在圖中頂點數組的索引,對應vertexs[20]的下標 11 ArchNode *nextarc; //指向下一條弧的指針 12 InfoTypde info; //比如弧的權重 13 }ArchNode; 14 15 typedef struct Vertex 16 { 17 VertexType data; //頂點信息 18 ArchNode *firstarc; //指向第一條弧的指針 19 }Vertex; 20 21 //這樣定義圖有個壞處,一旦定義好,圖中結點的個數就固定了! 22 typedef struct Graph 23 { 24 Vertex *vertexs[MAX_VERTEX_NUM]; //存儲頂點的數組,存放的是指向頂點的指針 25 int vexNum; //當前圖中的定點數 26 int arcNum; //當前圖中的弧的個數 27 int kind; //圖的種類,有向圖還是無向圖 28 }Graph;
//圖的創建
1 /* 2 初始條件:kind是圖的類型,目前有有向圖和無向圖 兩種. 3 返回值 :無。---大部分函數都無返回值,是對圖的引用進行操作的 4 */ 5 void createGraph(Graph *&G,int kind) 6 { 7 if(G) G = NULL; 8 G = (Graph *)malloc(sizeof(struct Graph)); 9 assert(NULL != G); 10 for(int i = 0; i < MAX_VERTEX_NUM; ++i) 11 { 12 G->vertexs[i] = NULL; //初始化指向頂點的指針為NULL 13 } 14 G->kind = kind; //設置圖的種類 15 G->vexNum = 0; //初始化圖中頂點的個數 16 G->arcNum = 0; //初始化圖中弧的個數 17 }
//圖的銷毀
1 /* 2 初始條件:G存在 3 返回值 :無。---大部分函數都無返回值,是對圖的引用進行操作的 4 */ 5 void destoryGraph(Graph *&G) 6 { 7 ArchNode *cur,*next; 8 if(NULL == G) 9 return; 10 //遍歷頂點 11 for(int i = 0; i < G->vexNum; ++i) 12 { 13 if(!G->vertexs[i]) 14 continue; 15 next = G->vertexs[i]->firstarc; 16 cur = G->vertexs[i]->firstarc; 17 while(cur) 18 { 19 next = cur->nextarc; 20 free(cur); 21 cur = next; 22 } 23 G->vertexs[i]->firstarc = NULL; 24 } 25 free(G); 26 G = NULL; 27 }
//向圖中增加結點
1 //向圖中增加結點 2 /* 3 初始條件:G存在,data是結點的數據值 4 */ 5 void addVertexToGraph(Graph *&G,VertexType data) 6 { 7 if(G->vexNum >= MAX_VERTEX_NUM) 8 { 9 cout << "Too many vertex!" << endl; 10 return ; 11 } 12 for(int i = 0; i < G->vexNum; ++i) 13 { 14 if(!G->vertexs[i]) 15 continue; 16 if(G->vertexs[i]->data == data) 17 { 18 cout << "Already exists!" << endl; 19 return; //不允許重復 20 } 21 } 22 Vertex *pVeterx; 23 pVeterx = (Vertex *)malloc(sizeof(struct Vertex)); 24 pVeterx->data = data; 25 pVeterx->firstarc = NULL; 26 G->vertexs[G->vexNum] = pVeterx; 27 G->vexNum++; 28 }
//從圖中刪除一個結點
1 void delVertexFromGraph(Graph *&G,VertexType data) 2 { 3 bool haveThisVertex = false; 4 ArchNode *cur,*next,*temp,*pre; 5 Vertex *anotherVertex; 6 if(NULL == G) 7 return; 8 if(G->vexNum <= 0) 9 { 10 cout << "Have no vertex!" << endl; 11 return ; 12 } 13 for(int i = 0; i < G->vexNum; ++i) 14 { 15 if(!G->vertexs[i]) 16 continue; 17 if(G->vertexs[i]->data == data) 18 { 19 haveThisVertex = true; 20 //以下循環用來刪除頂點所指向的弧鏈表 21 next = cur = G->vertexs[i]->firstarc; 22 if(G->kind == DIGRAPH) //如果是有向圖 23 { 24 while(cur) 25 { 26 next = cur->nextarc; 27 free(cur); 28 G->arcNum --; //弧的個數減一 29 cur = next; 30 } 31 G->vertexs[i] = NULL; 32 } 33 else if(G->kind == UNDIGRAPH) //如果是無向圖,這個麻煩點 34 { 35 while(cur) 36 { 37 //找到待刪除的弧的另一個結點,將它的弧鏈表中指向被刪除結點的弧也刪掉 38 anotherVertex = G->vertexs[cur->vertexIndex]; //找到待刪除弧對應的另一個結點 39 temp = anotherVertex->firstarc,pre = NULL; 40 while(temp) //這個循環是為了刪除另一個結點中保存弧信息 41 { 42 if(temp->vertexIndex == i) 43 { 44 //如果是首節點 45 if(NULL == pre) //或者if(NULL == pre) 46 { 47 anotherVertex->firstarc = temp->nextarc; 48 free(temp); 49 } 50 else 51 { 52 pre->nextarc = temp->nextarc; 53 free(temp); 54 } 55 break; //找到即停止循環 56 } 57 pre = temp; 58 temp = temp->nextarc; 59 } 60 next = cur->nextarc; 61 free(cur); 62 G->arcNum --; //弧的個數減一 63 cur = next; 64 } 65 G->vertexs[i] = NULL; 66 } 67 for(int j = i; j < G->vexNum - 1; ++j) 68 { 69 G->vertexs[j] = G->vertexs[j + 1]; 70 } 71 G->vertexs[j] = NULL; // 72 G->vexNum-- ; //結點的個數減一 73 break; 74 } 75 } 76 if(!haveThisVertex) 77 cout << "沒有該結點!" << endl; 78 }
//從圖中查找一個值為指定值的結點的索引
1 //初始條件:G存在,data是指定結點的數據值 2 int findVertexIndexInGraph(const Graph *G,VertexType data) 3 { 4 if(NULL == G) 5 return -1; 6 for(int i = 0; i < G->vexNum; ++i) 7 { 8 if(!G->vertexs[i]) 9 continue; 10 if(G->vertexs[i]->data == data) 11 { 12 return i; 13 break; 14 } 15 } 16 return -1; 17 }
//向圖中增加一條弧,有有向圖和無向圖之分
1 //初始條件:G存在,指定起始點,和弧的權重 2 void addArchToGraph(Graph *&G,VertexType startData,VertexType endData,InfoTypde weight = 0) 3 { 4 ArchNode *pArchNode,*cur; 5 //先要找到start和end 6 if(NULL == G) 7 return; 8 int startVertexIndex = findVertexIndexInGraph(G,startData); 9 int endVertexIndex = findVertexIndexInGraph(G,endData); 10 cur = G->vertexs[startVertexIndex]->firstarc; 11 while(cur) 12 { 13 if(cur->vertexIndex == endVertexIndex) 14 { 15 cout << "Already have this arch!" << endl; 16 return ; 17 } 18 cur = cur->nextarc; 19 } 20 if(startVertexIndex >= 0 && endVertexIndex >= 0) 21 { 22 if(G->kind == DIGRAPH) //如果是有向圖 23 { 24 pArchNode = (ArchNode *)malloc(sizeof(struct ArchNode)); //創建一個弧結點 25 pArchNode->info = weight; 26 pArchNode->nextarc = NULL; 27 pArchNode->vertexIndex = endVertexIndex; 28 cur = G->vertexs[startVertexIndex]->firstarc; 29 if(NULL == cur) 30 { 31 G->vertexs[startVertexIndex]->firstarc = pArchNode; 32 } 33 else 34 { 35 while(cur->nextarc) 36 { 37 cur = cur->nextarc; 38 } 39 cur->nextarc = pArchNode; 40 } 41 G->arcNum ++; //弧的條數加一 42 } 43 else if(G->kind == UNDIGRAPH) //如果是無向圖 44 { 45 pArchNode = (ArchNode *)malloc(sizeof(struct ArchNode)); //創建一個弧結點 46 pArchNode->info = weight; 47 pArchNode->nextarc = NULL; 48 pArchNode->vertexIndex = endVertexIndex; 49 cur = G->vertexs[startVertexIndex]->firstarc; 50 if(NULL == cur) 51 { 52 G->vertexs[startVertexIndex]->firstarc = pArchNode; 53 } 54 else 55 { 56 while(cur->nextarc) 57 { 58 cur = cur->nextarc; 59 } 60 cur->nextarc = pArchNode; 61 } 62 pArchNode = (ArchNode *)malloc(sizeof(struct ArchNode)); //再創建一個弧結點 63 pArchNode->info = weight; 64 pArchNode->nextarc = NULL; 65 pArchNode->vertexIndex = startVertexIndex; 66 cur = G->vertexs[endVertexIndex]->firstarc; 67 if(NULL == cur) 68 { 69 G->vertexs[endVertexIndex]->firstarc = pArchNode; 70 } 71 else 72 { 73 while(cur->nextarc) 74 { 75 cur = cur->nextarc; 76 } 77 cur->nextarc = pArchNode; 78 } 79 G->arcNum ++; //弧的條數加一 80 } 81 } 82 else 83 { 84 cout << "起點或終點不存在!" << endl; 85 return ; 86 } 87 }
//從圖中刪除一條弧
1 //初始條件:G存在,指定要刪除弧連接的兩個頂點 2 void delArchFromGraph(Graph *&G,VertexType startData,VertexType endData) 3 { 4 ArchNode *cur,*pre; 5 //先要找到start和end 6 if(NULL == G) 7 return; 8 int startVertexIndex = findVertexIndexInGraph(G,startData); 9 int endVertexIndex = findVertexIndexInGraph(G,endData); 10 if(startVertexIndex >= 0 && endVertexIndex >= 0) 11 { 12 if(G->kind == DIGRAPH) 13 { 14 cur = G->vertexs[startVertexIndex]->firstarc,pre = NULL; 15 while(cur) 16 { 17 if(cur->vertexIndex == endVertexIndex) 18 { 19 break; 20 } 21 pre = cur; 22 cur = cur->nextarc; 23 } 24 if(NULL == cur) 25 { 26 cout << "這兩個結點之間沒有弧!" << endl; 27 return ; 28 } 29 else 30 { 31 if(NULL == pre) //是首節點 32 G->vertexs[startVertexIndex]->firstarc = cur->nextarc; 33 else 34 pre->nextarc = cur->nextarc; 35 free(cur); 36 G->arcNum --; 37 } 38 } 39 else if(G->kind == UNDIGRAPH) 40 { 41 cur = G->vertexs[startVertexIndex]->firstarc,pre = NULL; 42 while(cur) 43 { 44 if(cur->vertexIndex == endVertexIndex) 45 { 46 break; 47 } 48 pre = cur; 49 cur = cur->nextarc; 50 } 51 if(NULL == cur) 52 { 53 cout << "這兩個結點之間沒有弧!" << endl; 54 return ; 55 } 56 else 57 { 58 if(NULL == pre) //是首節點 59 G->vertexs[startVertexIndex]->firstarc = cur->nextarc; 60 else 61 pre->nextarc = cur->nextarc; 62 free(cur); 63 //G->arcNum --; 64 } 65 66 cur = G->vertexs[endVertexIndex]->firstarc,pre = NULL; 67 while(cur) 68 { 69 if(cur->vertexIndex == startVertexIndex) 70 { 71 break; 72 } 73 pre = cur; 74 cur = cur->nextarc; 75 } 76 if(NULL == cur) 77 { 78 cout << "這兩個結點之間沒有弧!" << endl; 79 return ; 80 } 81 else 82 { 83 if(NULL == pre) //是首節點 84 G->vertexs[endVertexIndex]->firstarc = cur->nextarc; 85 else 86 pre->nextarc = cur->nextarc; 87 free(cur); 88 G->arcNum --; 89 } 90 } 91 } 92 else 93 { 94 cout << "起點或終點不存在!" << endl; 95 return ; 96 } 97 }
//深度優先遍歷
1 //初始條件:圖G存在 2 void DFSdetails(const Graph *G,int i,int satusArr[]) 3 { 4 ArchNode *cur; 5 if(satusArr[i] == 1 ) 6 return; 7 cout << G->vertexs[i]->data << " "; 8 satusArr[i] = 1; 9 cur = G->vertexs[i]->firstarc; 10 while(cur) 11 { 12 DFSdetails(G,cur->vertexIndex,satusArr); 13 cur = cur->nextarc; 14 } 15 } 16 17 void DFS(const Graph *G) 18 { 19 int satusArr[MAX_VERTEX_NUM] = {0}; 20 cout << "深度優先遍歷:"; 21 if(NULL == G) 22 return; 23 for(int i = 0; i < G->vexNum; ++i) 24 { 25 DFSdetails(G,i,satusArr); 26 } 27 cout << endl; 28 }