数据结构 第七章 图
四种基本存储结构之邻接矩阵表示法
1 /* 2 * 范围:第七章 图 3 * 日期:2018/4/1 4 */ 5 6 /* 7 笔记: 8 enum < 枚举类型名> {< 枚举表>}; 9 enum day {Sun,Mon,Tue,Wed,Thu,Fri,Sat}; 10 day d1,d2,d3; 11 d1 = Thu; d2 = Sat; d3 = Tue; 12 定义为枚举类型的变量,只能取枚举表中的值,枚举的本质是整型类型。 13 */ 14 #include15 #define INFINITY INT_MAX 16 17 18 using namespace std; 19 // 数组表示法/邻接矩阵表示法 20 const int MAXSIZE = 20; 21 typedef char vertexType; 22 typedef int vrType; 23 typedef char infoType; 24 typedef enum{DG,DN,UDG,UDN} graphKind; 25 26 typedef struct arcCell 27 { 28 vrType adj; 29 infoType *info; 30 }arcCell,adjMatrix[MAXSIZE][MAXSIZE]; 31 32 typedef struct 33 { 34 vertexType vex[MAXSIZE]; 35 adjMatrix arc; 36 int vexnum,arcnum; 37 graphKind kind; 38 }MGraph; 39 40 int locate(MGraph &g,vertexType v) 41 { 42 for (int i=0;i ) 43 { 44 if( g.vex[i] == v) 45 return i; 46 } 47 return -1; 48 } 49 void createUDN(MGraph &g) 50 { 51 int hasInfo; 52 cout << "顶点数、边数、是否有信息"<<endl; 53 cin >> g.vexnum >>g.arcnum >> hasInfo; 54 int i,j; 55 for (i=0;i ) 56 { 57 cin >>g.vex[i]; 58 } 59 for (i=0;i ) 60 for (j=0;j ) 61 { 62 g.arc[i][j].adj = INFINITY; 63 g.arc[i][j].info = NULL; 64 } 65 vertexType v1,v2; 66 vrType w; 67 cout << "边:" <<endl; 68 for (int k=0;k ) 69 { 70 cin >>v1 >>v2>>w; 71 i = locate(g,v1); 72 j = locate(g,v2); 73 g.arc[i][j].adj = w; 74 if (hasInfo) 75 cin >> g.arc[i][j].info; 76 g.arc[j][i] = g.arc[i][j]; 77 } 78 } 79 void createGraph(MGraph &g) 80 { 81 graphKind kind; 82 cout << "graphkind"<<endl ; 83 cin >> (int &)kind; 84 switch(kind) 85 { 86 case UDN:createUDN(g); 87 } 88 } 89 void printMatrix(MGraph &g) 90 { 91 int i,j; 92 for (i=0;i< g.vexnum ; i++) 93 { 94 for (j = 0 ;j ) 95 { 96 if (g.arc[i][j].adj == INFINITY) 97 cout << '#' << ' '; 98 else 99 cout << g.arc[i][j].adj <<' '; 100 } 101 cout <<endl; 102 } 103 104 } 105 // 深度优先搜索 106 bool visited[MAXSIZE]; 107 108 int firstAdjVex(MGraph &g,int v) 109 { 110 // 邻接矩阵表示法中,点v的第一个邻接点,在矩阵中横着找不为无穷大的点 111 int j; 112 for (j = 0; j < g.vexnum ; j++) 113 { 114 if (g.arc[v][j].adj!=INFINITY) 115 return j; 116 } 117 return -1; 118 } 119 int nextAdjVex(MGraph &g,int v,int w) 120 { 121 // v的邻接点中在w之后的第一个邻接点 122 int j; 123 for (j = w+1;j ) 124 { 125 if (g.arc[v][j].adj!=INFINITY) 126 return j; 127 } 128 return -1; 129 } 130 void DFS(MGraph &g,int v) 131 { 132 visited[v] = true; // 从V结点开始深度搜索 133 cout << g.vex[v] << ' '; 134 for (int w = firstAdjVex(g,v); w >= 0 ;w = nextAdjVex(g,v,w)) 135 { 136 if (!visited[w]) 137 DFS(g,w);// 对未被访问过的邻接点递归调用DFS 138 } 139 } 140 void DFSTraverse(MGraph &g) 141 { 142 int i; 143 for (i=0;i ) 144 visited[i] = false; // 初始化visited,均未被访问 145 for (i=0;i // 一次寻找后可能有仍旧未被访问的点 146 { 147 if (!visited[i]) 148 DFS(g,i); 149 } 150 151 } 152 int main() 153 { 154 MGraph g; 155 createGraph(g); 156 // printMatrix(g); 157 DFSTraverse(g); 158 159 return 0; 160 }
邻接表表示法
1 /* 2 * 范围:第七章 图 3 * 日期:2018/4/1 4 */ 5 6 /* 7 笔记: 8 enum < 枚举类型名> {< 枚举表>}; 9 enum day {Sun,Mon,Tue,Wed,Thu,Fri,Sat}; 10 day d1,d2,d3; 11 d1 = Thu; d2 = Sat; d3 = Tue; 12 定义为枚举类型的变量,只能取枚举表中的值,枚举的本质是整型类型。 13 */ 14 #include15 #include <string> 16 #include 17 #define INFINITY INT_MAX 18 19 20 using namespace std; 21 22 // 邻接表 23 24 const int MAXSIZE = 20; 25 26 typedef char vertexType; 27 typedef char infoType; 28 typedef enum{DG,UDG} graphKind; 29 30 typedef struct arcNode 31 { 32 int adjvex; 33 infoType *info; 34 struct arcNode *nextarc; 35 }arcNode; 36 37 typedef struct 38 { 39 vertexType data; 40 struct arcNode *firstarc; 41 }VNode; 42 43 typedef struct 44 { 45 VNode adjList[MAXSIZE]; 46 int vexnum,arcnum; 47 graphKind kind; 48 }ALGraph; 49 50 int locate(ALGraph &g,vertexType v) 51 { 52 int i; 53 for (i = 0;i ) 54 { 55 if ( g.adjList[i].data == v ) 56 return i; 57 } 58 return -1; 59 } 60 61 void createUDG(ALGraph &g) 62 { 63 int hasInfo; 64 cout << "顶点数、边数、是否有信息"<<endl; 65 cin >> g.vexnum >> g.arcnum>>hasInfo; 66 int i,j,k; 67 cout << "头结点" <<endl; 68 for (i=0;i ) 69 { 70 cin >> g.adjList[i].data ; 71 g.adjList[i].firstarc = NULL; 72 } 73 vertexType v1,v2; 74 arcNode *p,*q; 75 cout << "边:" <<endl; 76 for (k = 0; k < g.arcnum;k++) 77 { // 头插法建立链表 78 cin >> v1 >> v2; 79 i = locate(g,v1); 80 j = locate(g,v2); 81 p = (arcNode*)malloc(sizeof(arcNode)); 82 if (hasInfo) 83 cin >> p->info; 84 p->adjvex = j; 85 p->nextarc = g.adjList[i].firstarc; 86 g.adjList[i].firstarc = p; 87 88 // 无向图一条边建立两个节点 89 q = (arcNode*)malloc(sizeof(arcNode)); 90 if (hasInfo) 91 q->info = p->info; 92 q->adjvex = i; 93 q->nextarc = g.adjList[j].firstarc; 94 g.adjList[j].firstarc = q; 95 } 96 } 97 98 void createDG(ALGraph &g) 99 { 100 int hasInfo; 101 cout << "顶点数、弧数、有无信息"<<endl; 102 cin >>g.vexnum >>g.arcnum >> hasInfo; 103 104 int i,j,k; 105 cout << "顶点" <<endl; 106 for (i=0;i ) 107 { 108 cin >> g.adjList[i].data; 109 g.adjList[i].firstarc = NULL; 110 } 111 arcNode *p; 112 vertexType v1,v2; 113 cout << "弧" <<endl ; 114 for (k = 0;k ) 115 { 116 cin >>v1>>v2; 117 i = locate(g,v1); 118 j = locate(g,v2); 119 p = (arcNode*)malloc(sizeof(arcNode)); 120 p->adjvex = j; 121 p->nextarc = g.adjList[i].firstarc; 122 if (hasInfo) 123 cin >> p->info; 124 g.adjList[i].firstarc = p; 125 } 126 127 128 } 129 130 void buildNALG(ALGraph &g,ALGraph &ng) 131 { 132 ng.vexnum = g.vexnum; 133 ng.arcnum = g.arcnum; 134 135 int i,j; 136 for (i=0;i ) 137 { 138 ng.adjList[i].data = g.adjList[i].data; 139 ng.adjList[i].firstarc = NULL; 140 } 141 arcNode *p,*q; 142 for (i = 0;i ) 143 { 144 for (j = 0;j ) 145 { 146 if (i==j) 147 continue; 148 p = g.adjList[j].firstarc; 149 while (p) 150 { 151 if (p->adjvex == i) 152 { 153 q = (arcNode *)malloc(sizeof(arcNode)); 154 q->adjvex = j; 155 q->info = p->info; 156 q->nextarc = ng.adjList[i].firstarc; 157 ng.adjList[i].firstarc = q; 158 } 159 p = p->nextarc; 160 } 161 162 } 163 } 164 } 165 166 void createGraph(ALGraph &g) 167 { 168 graphKind kind; 169 cout << "kind:"<<endl; 170 cin >> (int &)kind; 171 switch(kind) 172 { 173 case UDG:createUDG(g);break; 174 case DG:createDG(g); 175 } 176 } 177 void printGraph(ALGraph &g) 178 { 179 int i; 180 arcNode *p; 181 for (i=0;i ) 182 { 183 if (!g.adjList[i].firstarc) 184 cout < "->NULL"; 185 else 186 cout << g.adjList[i].data <<"->"; 187 p = g.adjList[i].firstarc; 188 while (p) 189 { 190 if (!p->nextarc) 191 cout < adjvex; 192 else 193 cout < adjvex << "->"; 194 p = p->nextarc; 195 } 196 cout <<endl; 197 } 198 199 } 200 // 深度优先搜索 201 bool visited[MAXSIZE]; 202 203 int firstAdjVex(ALGraph &g,int v) 204 { 205 if (g.adjList[v].firstarc) 206 return g.adjList[v].firstarc->adjvex; 207 else 208 return -1; 209 } 210 int nextAdjVex(ALGraph &g,int v,int w) 211 { 212 arcNode *p; 213 p = g.adjList[v].firstarc; 214 for (p ; p ; p = p ->nextarc) 215 { 216 if (p->adjvex == w) 217 { 218 if (p->nextarc) 219 { 220 return p->nextarc->adjvex; 221 } 222 else 223 return -1; 224 } 225 } 226 } 227 void DFS(ALGraph &g,int v) 228 { 229 visited[v] = true; 230 cout << g.adjList[v].data<<' '; 231 for (int w = firstAdjVex(g,v) ; w>=0 ; w = nextAdjVex(g,v,w)) // 注意这里不能写w,因为我的return值是-1!所以条件亦成立 232 { 233 if (!visited[w]) 234 DFS(g,w); 235 } 236 } 237 void DFSTraverse(ALGraph &g) 238 { 239 int i; 240 for (i=0;i ) 241 { 242 visited[i] = false; 243 } 244 for (i = 0;i ) 245 { 246 if (!visited[i]) 247 DFS(g,i); 248 } 249 } 250 251 // 广度优先搜索 252 void BFSTraverse(ALGraph &g) 253 { 254 for (int i = 0;i ) 255 visited[i] = false; 256 queue<int> que; 257 for (int i = 0;i ) 258 { 259 if (!visited[i]) 260 { 261 visited[i] = true; 262 cout << g.adjList[i].data<<' '; 263 que.push(i); 264 while (!que.empty()) 265 { 266 int u = que.front(); 267 que.pop(); 268 for (int w = firstAdjVex(g,u) ; w >=0 ;w= nextAdjVex(g,u,w)) 269 { 270 if (!visited[w]) 271 { 272 visited[w] = true; 273 cout << g.adjList[w].data <<' '; 274 que.push(w); 275 } 276 } 277 } 278 } 279 } 280 } 281 int main() 282 { 283 ALGraph g,ng; 284 createGraph(g); 285 //buildNALG(g,ng); 286 printGraph(g); 287 DFSTraverse(g); 288 289 290 return 0; 291 }
十字链表表示法
1 /* 2 * 范围:第七章 图 3 * 日期:2018/4/1 4 */ 5 6 /* 7 笔记: 8 enum < 枚举类型名> {< 枚举表>}; 9 enum day {Sun,Mon,Tue,Wed,Thu,Fri,Sat}; 10 day d1,d2,d3; 11 d1 = Thu; d2 = Sat; d3 = Tue; 12 定义为枚举类型的变量,只能取枚举表中的值,枚举的本质是整型类型。 13 */ 14 #include15 #include <string> 16 #include 17 18 19 using namespace std; 20 // 十字链表 21 const int MAXSIZE = 20; 22 23 typedef char vertexType; 24 typedef char infoType; 25 26 typedef struct arcNode 27 { 28 int tailvex,headvex;//尾部邻接点和头部邻接点 29 struct arcNode *hlink,*tlink;//hlink指向弧头相同的下一条弧 30 infoType *info; 31 }arcNode; 32 33 typedef struct 34 { 35 vertexType data; 36 struct arcNode *firstin,*firstout; 37 }VNode; 38 39 typedef struct 40 { 41 int vexnum,arcnum; 42 VNode olist[MAXSIZE]; 43 }OLGraph; 44 45 int locate(OLGraph &g,vertexType v) 46 { 47 int i; 48 for (i=0;i ) 49 { 50 if ( g.olist[i].data == v ) 51 return i; 52 }return -1; 53 } 54 void createDG(OLGraph &g) 55 { 56 cout << "顶点数、弧数、有无信息" << endl; 57 int hasInfo; 58 cin >> g.vexnum >>g.arcnum >> hasInfo; 59 int i,j,k; 60 cout << "顶点:" << endl; 61 for (i=0;i ) 62 { 63 cin >> g.olist[i].data; 64 g.olist[i].firstin = NULL; 65 g.olist[i].firstout = NULL; 66 } 67 cout << "弧:"<<endl; 68 vertexType v1,v2; 69 arcNode *p; 70 for (k = 0;k ) 71 { 72 cin >> v1 >> v2;a 73 i = locate(g,v1); 74 j = locate(g,v2); 75 p->tailvex = i; 76 p->headvex = j; 77 if (hasInfo) 78 cin >> p->info; 79 p->tlink = g.olist[i].firstout; 80 g.olist[i].firstout = p; 81 // 至此完成邻接表的工作,十字链表即为邻接表+逆邻接表的结合体 82 p->hlink = g.olist[j].firstin; 83 g.olist[j].firstin = p; 84 } 85 } 86 int main() 87 { 88 89 90 91 return 0; 92 }
邻接多重表表示法
1 /* 2 * 范围:第七章 图 3 * 日期:2018/4/1 4 */ 5 6 /* 7 笔记: 8 enum < 枚举类型名> {< 枚举表>}; 9 enum day {Sun,Mon,Tue,Wed,Thu,Fri,Sat}; 10 day d1,d2,d3; 11 d1 = Thu; d2 = Sat; d3 = Tue; 12 定义为枚举类型的变量,只能取枚举表中的值,枚举的本质是整型类型。 13 */ 14 #include15 #include <string> 16 #include 17 18 19 using namespace std; 20 // 邻接多重表 无向图的存储形式 21 const int MAXSIZE = 20; 22 typedef char vertexType; 23 24 typedef struct eNode 25 { 26 bool mark; 27 int ivex,jvex; 28 struct eNode *ilink,*jlink; // ilink 指向依附于ivex的边 29 }eNode; 30 31 typedef struct VNode 32 { 33 vertexType data; 34 struct eNode *firstedge; 35 }VNode; 36 37 typedef struct 38 { 39 VNode adjmulist[MAXSIZE]; 40 int vexnum,edgenum; 41 }AMLGraph; 42 43 void createAMLGraph(AMLGraph &g) 44 { 45 cout << "顶点数、边数、有无信息"<<endl; 46 int hasInfo; 47 cin >> g.vexnum >> g.edgenum >> hasInfo; 48 49 int i,j,k; 50 for (i=0;i ) 51 { 52 cin >> g.adjmulist[i].data; 53 g.adjmulist[i].firstedge = NULL; 54 } 55 56 eNode *p; 57 vertexType v1,v2; 58 for (k=0;k ) 59 { 60 cin >> v1 >> v2; 61 i = locate(g,v1); 62 j = locate(g,v2); 63 p = (eNode *)malloc(sizeof(eNode)); 64 p->ivex = i; 65 p->jvex = j; 66 p->ilink = g.adjmulist[i].firstedge; 67 p->jlink = g.adjmulist[j].firstedge; 68 g.adjmulist[i].firstedge = p; 69 g.adjmulist[j].firstedge = p; 70 } 71 } 72 int main() 73 { 74 75 76 77 return 0; 78 }
无向图的连通分量和生成树
1 /* 2 * 7.4 知识点 3 * 1. 遍历无向图时,对于连通图,从任一顶点出发进行深度或广度优先搜索即可;对于非联通图则需要从 4 * 多个顶点出发进行搜索,每次获得的顶点序列则为各个连通分量的顶点集。 5 * 2. 连通图有深度优先生成树和广度优先生成树,即搜索的路径形成的树。 6 * 3. 非连通图每个连通分量均可形成一个生成树,即一个生成森林。 7 * 4. 除了二叉树外的没有叉数限制的树一般用孩子-兄弟表示法表示成方便遍历的二叉树形式。 8 * 5. 森林的树的根节点其实亦为兄弟,也可以用孩子-兄弟表示法来表示。 9 */ 10 // 无向图的深度优先生成森林(非连通图) 11 12 typedef char Elemtype; 13 typedef struct CSNode 14 { 15 Elemtype data; 16 struct CSNode *child,*sibling; 17 }CSNode,*CSTree; 18 19 20 void DFSTree(ALGraph &g,CSTree &t,int v) 21 { 22 // 从v顶点开始深度搜索生成树 23 visited[v] = true; 24 cout <' '; 25 CSTree p,q; 26 bool isfirst = true; 27 for (int w = firstAdjVex(g,v) ; w>=0 ; w = nextAdjVex(g,v,w)) 28 { 29 if (!visited[w]) 30 { 31 p = (CSTree)malloc(sizeof(CSNode)); 32 p->data = g.adjList[w].data; 33 p->child = NULL; 34 p->sibling = NULL; 35 // 创建新节点P作为根节点T的邻接点,但必须确定是第一个邻接点还是其他 36 if (isfirst) 37 { 38 t->child = p; 39 isfirst = false; 40 }else 41 { 42 q->sibling = p; 43 } 44 q = p; 45 DFSTree(g,p,w); // 递归寻找p的邻接点们! 46 47 } 48 } 49 } 50 void DFSForest(ALGraph &g,CSTree &t) 51 { 52 for (int i=0;i ) 53 visited[i] = false; 54 CSTree p,q; 55 for (int i=0;i ) 56 { 57 if (!visited[i]) 58 { 59 p = (CSTree)malloc(sizeof(CSNode)); 60 p->data = g.adjList[i].data; 61 p->child = NULL; 62 p->sibling = NULL; 63 if (!t) 64 { 65 t = p; // 第一棵生成树 66 }else 67 { 68 q->sibling = p; // 非第一棵生成树,则为上一棵生成树根节点的兄弟 69 } 70 q = p; 71 DFSTree(g,p,i);// 从i顶点出发建立以p为根节点的生成子树 72 } 73 } 74 75 76 } 77 void level(CSTree &t) 78 { 79 queue q; 80 CSTree p; 81 if (t) // 空树没有必要遍历了 82 { 83 q.push(t); // 根节点入队 84 while (!q.empty()) 85 { 86 p = q.front(); // 弹栈一个元素 87 q.pop(); 88 cout << p->data << ' '; 89 90 if (p->child) 91 { 92 q.push(p->child); 93 } 94 if (p->sibling) 95 { 96 q.push(p->sibling); 97 } 98 } 99 } 100 }
测试数据
3
13 13 0
ABCDEFGHIJKLM
A C
A F
A L
A B
B M
D E
G H
G K
G I
H K
J L
J M
M L
最小生成树 之 普利姆算法
1 struct 2 { 3 vertexType adjvex; 4 vrType lowcost; 5 }closedge[MAXSIZE]; 6 // 辅助数组的意义:记录从U到V-U中具有最小代价的边 7 8 int locateVex(MGraph &g,vertexType v) 9 { 10 int k = -1; 11 for (int i = 0 ;i) 12 { 13 if (g.vex[i] == v) 14 k = i; 15 return k; 16 } 17 return k; 18 } 19 20 int minimum(MGraph &g) 21 { 22 int min1 = INFINITY; 23 int k = -1; 24 25 for (int i = 0;i ) 26 { 27 if ( closedge[i].lowcost != 0 ) 28 { 29 if ( closedge[i].lowcost < min1 ) 30 { 31 min1 = closedge[i].lowcost; 32 k = i; 33 } 34 } 35 } 36 return k; 37 } 38 39 void miniSpanTree_prim(MGraph &g,vertexType u) 40 { 41 42 int k = locate(g,u); 43 for (int i=0;i ) 44 { // closedge 一开始并不包含K 45 if (i != k ) 46 { 47 closedge[i].adjvex = u; 48 closedge[i].lowcost = g.arc[k][i].adj; //不与u邻接的点的lowcost是INFINITY 49 } 50 } 51 closedge[k].lowcost = 0; // 被选入U的顶点的权值均为0 52 53 for (int i = 1;i // 选择g.vexnum -1此V-U中的顶点,直到U = V为止 54 { 55 // 选择最小的权值,把顶点加入到U中 56 k = minimum(g); // 求出下一个结点K 57 cout <<"( " < " , "< " )" << endl; // 打印找到的边 58 closedge[k].lowcost = 0; // 把K划入U集合中 59 // 更新closedge 60 for (int j = 0;j ) 61 { 62 if (g.arc[k][j].adj < closedge[j].lowcost) 63 { 64 closedge[j].adjvex = g.vex[k]; 65 closedge[j].lowcost = g.arc[k][j].adj; 66 } 67 } 68 69 } 70 }
测试数据:
3
6 10 0
ABCDEF
A B 6
A D 5
A C 1
B C 5
B E 3
C D 5
C E 6
C F 4
D F 2
E F 6
拓扑排序
1 /* 2 有向无环图的介绍: 3 1. 有向无环图:描述含有公共子式的工具,实现对相同子式地共享,从而节省存储空间 4 2. 检查一个有向图是否存在环比无向图复杂。无向图:深度优先遍历过程中遇到已访问过的顶点的边则必定存在环; 5 有向图:这条回边有可能是指向深度优先生成森林中另一棵生成树顶点的弧。 6 解决:从某个顶点V出发的遍历,在DFS(V)结束之前出现一条从顶点U到顶点V的回边,有向图上必定存在环。 7 3. 有向无环图是描述一项工程或系统的进行过程的有效工具。工程可分为若干个活动,活动之间存在条件的约束。 8 人们关心:1)工程能否顺利完成 2)工程完成所必须的最短时间 9 10 拓扑排序: 11 1. 由某个集合上的一个偏序得到该集合的一个全序的过程 12 2. 解释:偏序是指集合中仅有部分成员之间可比较,而全序为集合中全体成员之间均可比较,全序即为拓扑有序 13 3. 由偏序定义得到拓扑有序的操作便是拓扑排序 14 4. 顶点表示活动,弧表示活动之间优先关系的有向图称为顶点表示活动的网AOV网,直接前驱和直接后继 15 5. 在AOV网中不应该出现有向环,因此检测有向网中是否存在环的方法是:构造顶点的拓扑排序序列,若网中的所有顶点都在拓扑有序序列中则必定不存在环。 16 6. 如何进行拓扑排序?在有向图中选择一个没有前驱的顶点且输出,删除该顶点和所有以它为尾的弧 17 18 */ 19 int indegree[MAXSIZE]; 20 void findInDegree(ALGraph &g) 21 { 22 ALGraph ng; 23 buildNALG(g,ng); 24 arcNode *p; 25 int d = 0; 26 for (int i=0;i) 27 { 28 d = 0; 29 p = ng.adjList[i].firstarc; 30 while (p) 31 { 32 d ++ ; 33 p = p->nextarc; 34 } 35 indegree[i] = d; 36 } 37 // for (int i=0;i 38 // cout < 39 } 40 int topoLogicalSort(ALGraph &g) 41 { 42 findInDegree(g); // 找到各定点的入度 43 stack<int> st; 44 // 把所有入度为0的顶点入栈 45 for (int i =0;i 46 { 47 if (!indegree[i]) 48 st.push(i); 49 } 50 int i; 51 arcNode *p; 52 int count = 0 ; // 对输出顶点计数 53 while (!st.empty()) 54 { 55 i = st.top(); 56 st.pop(); 57 cout << g.adjList[i].data << ' '; 58 count ++; 59 for (p = g.adjList[i].firstarc ; p ; p=p->nextarc) 60 { 61 // 对I号顶点的每个邻接点的入度都减1 62 int k = p->adjvex; 63 if (!(--indegree[k])) 64 st.push(k); // 若减1后变为入度为0,入栈 65 } 66 } 67 if (count < g.vexnum) 68 return -1; 69 else 70 return 1; 71 })
关键路径
1 int ve[MAXSIZE]; // 各顶点的最早开始时间 2 int vl[MAXSIZE]; // 各顶点的最迟开始时间 3 4 /* 5 1. 计算各顶点的最早开始时间ve 6 2. T为拓扑序列顶点栈 7 3. S为零入度顶点栈 8 4. 若G无回路,则用栈T返回G的一个拓扑序列 9 */ 10 int topoLogicalOrder(ALGraph &g,stack<int> &t) 11 { 12 findInDegree(g,indegree); 13 stack<int> s; 14 for (int i = 0;i) 15 { 16 if (!indegree[i]) 17 s.push(i); 18 } 19 int count = 0; 20 for (int i=0;i ) 21 ve[i] = 0; 22 while (!s.empty()) 23 { 24 int j = s.top(); 25 s.pop(); 26 t.push(j); 27 count ++ ; 28 for (arcNode *p = g->adjList[j].firstarc ; p ; p = p->nextarc) 29 { 30 int k = p->adjvex; 31 if (!(--indegree[k])) 32 s.push(k); 33 if (ve[j]+*(p->info) > ve[k]) 34 ve[k] = ve[j] + *(p->info); 35 } 36 } 37 if (count <g.vexnum) 38 return -1; 39 else return 1; 40 } 41 42 // 关键路径 43 int criticalPath(ALGraph &g) 44 { 45 // 目的:输出G的各项关键活动 46 stack<int> t; 47 arcNode *p; 48 if (!topoLogicalOrder(g,t)) 49 return -1; 50 for (int i=0;i ) 51 vl[i] = ve[g.vexnum-1] ; // 初始化均为最大值 52 while (!t.empty()) 53 { 54 int j = t.top(); 55 t.pop(); 56 for (p = g.adjList[j].firstarc ; p ; p= p->nextarc) 57 { 58 int k = p->adjvex; 59 dut = *(p->info); 60 if (vl[k]-dut < vl[j]) 61 vl[j] = vl[k] - dut; 62 } 63 } 64 for (j = 0;j ) 65 { 66 for (p = g.adjList[i].firstarc ; p;p=p->nextarc) 67 { 68 int k = p->adjvex; 69 dut = *(p->info); 70 int ee = ve[j]; 71 el = vl[k] - dut; 72 tag = (ee == el) > 73 74 } 75 } 76 77 78 79 }
最短路径-迪杰斯特拉
1 /* 最短路径 2 1. 交通路网上从原点A到达目的地B的所含边的数目最少的路径,只需要广度优先搜索,遇到B点时停止 3 2. 源点到其余各个顶点的最短路径--迪杰斯特拉算法--按照路径长度递增的次序产生最短路径的算法 4 3. 求从源点v0到其余各点v的最短路径P[v]和带权长度d[v] 5 4. p[v][w] == true, 则w是v0 - v 上最短路径的一个顶点,该路径显然经过v0 和 v\ 6 5. final[v]为已经归入点集合的点 7 */ 8 bool p[MAXSIZE][MAXSIZE]; 9 int d[MAXSIZE]; 10 bool final[MAXSIZE]; 11 12 void shortestPath(MGraph &g,int v0) 13 { 14 15 for (int i=0;i) 16 { 17 final[i] = false; 18 d[i] = g.arc[v0][i].adj; 19 for (int j = 0;j ) 20 p[i][j] = false; 21 22 if (d[i]!=INFINITY) 23 { 24 p[i][i] = true; 25 p[i][v0] = true; 26 } 27 } 28 final[v0] = true; 29 d[v0] = 0; 30 int v; 31 int min = INFINITY; 32 for (int i=1;i < g.vexnum;i++) 33 { // 对其余的g.vexnum - 1个顶点,每次选择最短的一条路径的顶点加入final集合 34 min = INFINITY; 35 for (int j=0;j ) 36 if (!final[j]) 37 if (d[j] < min) 38 { 39 min = d[j]; 40 v = j; // v是此次选出的顶点 41 } 42 final[v] = true; 43 // 更新最短路径及距离 44 for (int j = 0;j ) 45 { 46 if (!final[j] && d[j] > (g.arc[v][j].adj + min)) //此处注意INFINIT + INT 不会小于 INFINIT,因为已经到了能存储的最大数 47 { 48 d[j] = min + g.arc[v][j].adj; 49 for (int k = 0;k ) 50 p[j][k] = p[v][k]; 51 p[j][j] = true; 52 } 53 } 54 } 55 } 56 57 void printShortestPath(MGraph &g) 58 { 59 int i; 60 for (i = 1;i ) 61 { 62 cout << g.vex[i] << "\t"<<'('; 63 for (int j = 0;j ) 64 if (p[i][j]) 65 cout << g.vex[j] <<' ' ; 66 cout << ')'<<"\t" ; 67 cout << d[i] <<endl; 68 } 69 }
测试数据
// 迪杰特斯拉
1
6 8 0
ABCDEF
A C 10
A E 30
A F 100
B C 5
C D 50
E D 20
E F 60
D F 10