标签:
graph.h
#ifndef __GRAPH__ #define __GRAPH__ #include <iostream> #include <queue> using namespace std; class DisjointSet; template <class TypeOfEdge> class Graph { public: virtual bool insert(int u, int v, TypeOfEdge weight) = 0; virtual bool remove(int u, int v) = 0; virtual bool modify(int u, int v, TypeOfEdge weight) = 0; virtual bool exist(int u, int v) const = 0; virtual int numOfVer() const {return vers;} virtual int numOfEdge() const {return edges;} protected: int vers; int edges; }; //有向加权图的邻接表实现 //作为无权图使用时,可将weight置1,权值一样 //作为无向图使用时,插入和删除时需将两个方向的边均插入或删除,修改weight时同样 template <class TypeOfVer, class TypeOfEdge> class AdjListGraph : public Graph<TypeOfEdge>{ public: //这里为了方便,所有成员函数写成内联函数的形式 //构造一个只有结点没有边的图 AdjListGraph(int v, const TypeOfVer *d, bool isWeightedFlag, bool isDirectedFlag){ vers = v; edges = 0; isWeighted = isWeightedFlag; isDirected = isDirectedFlag; verList = new VerNode[vers]; for (int i = 0; i < vers; ++i) { verList[i].ver = d[i]; } } ~AdjListGraph(){ for (int i = 0; i < vers; ++i) { EdgeNode *p, *pre; p = verList[i].head; while (p != NULL){ pre = p; p = p->next; delete pre; } } delete [] verList; } bool insert(int u, int v, TypeOfEdge weight = 0) { if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1) return false; if (exist(u, v)) return false; verList[u].head = new EdgeNode(v, weight, verList[u].head); if (!isDirected) verList[v].head = new EdgeNode(u, weight, verList[v].head); ++edges; return true; } bool remove(int u, int v) { bool flag = removeCore(u, v); if (!isDirected) flag &= removeCore(v, u); return flag; } bool removeCore(int u, int v) { if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1) return false; EdgeNode *p = verList[u].head; if (p == NULL){ return false; } //删除结点为头结点 if (p->end == v){ verList[u].head = p->next; delete p; --edges; return true; } //找到删除结点或找不到 EdgeNode *pre = p; p = p->next; while (p != NULL && p->end != v) { pre = p; p = p->next; } //找不到 if (p == NULL){ return false; } //找到 pre->next = p->next; delete p; --edges; return true; } bool modify(int u, int v, TypeOfEdge weight) { bool flag = modifyCore(u, v, weight); if (!isDirected) flag &= modifyCore(v, u, weight); return flag; } bool modifyCore(int u, int v, TypeOfEdge weight) { EdgeNode *p = verList[u].head; while (p != NULL && p->end != v) { p = p->next; } if (p == NULL) { return false; } p->weight = weight; return true; } bool exist(int u, int v) const { EdgeNode *p = verList[u].head; while (p != NULL && p->end != v) { p = p->next; } if (p == NULL) { return false; } return true; } //深度优先遍历 void dfs(int startVer = 0) const { bool *visited = new bool[vers]; for (int i = 0; i < vers; ++i) visited[i] = false; int j = 0; for (int i = startVer; i < vers + startVer; ++i){ j = i % vers; if (visited[j]) continue; dfsCore(j, visited); cout << endl; //每一行为一棵深度优先生成树 } } //广度优先遍历 void bfs(int startVer = 0) const { bool *visited = new bool[vers]; for (int i = 0; i < vers; ++i) visited[i] = false; queue<int> q; int j = 0; for (int i = startVer; i < vers + startVer; ++i){ j = i % vers; if (visited[j]) continue; q.push(j); while (!q.empty()) { //访问当前结点 int v = q.front(); q.pop(); if (visited[v]) continue; cout << verList[v].ver << '\t'; visited[v] = true; //当前结点的后继结点放入队列 EdgeNode *p = verList[v].head; while (p != NULL) { if (!visited[p->end]) { q.push(p->end); } p = p->next; } } cout << endl; //每一行为一棵广度优先生成树 } } //欧拉回路 void eulerCircuit(TypeOfVer start) { if (edges == 0) return; for (int i = 0; i < vers; ++i) { int degree = 0; EdgeNode *p = verList[i].head; while (p != NULL) { ++degree; p = p->next; } //度数为0或奇数,不存在欧拉回路 if ((degree == 0) || (degree & 0x1)) return; } //找到起始点序号 int iStart = 0; for (iStart = 0; iStart < vers; ++iStart){ if (verList[iStart].ver == start) break; } if (iStart == vers) return; //保存一个备份 VerNode *tmp = clone(); //找到第一条路径(起点所有的边已被访问) EulerNode *beg, *end; eulerCircuitCore(iStart, beg, end); EulerNode *p, *pre; while (true) { pre = beg; p = beg->next; while (p != NULL) { if (verList[p->nodeNum].head != NULL) break; pre = p; p = p->next; } if (p == NULL) break; //从某一个未访问的边开始找一条路径 EulerNode *begTmp, *endTmp; eulerCircuitCore(p->nodeNum, begTmp, endTmp); pre->next = begTmp; endTmp->next = p->next; delete p; } //恢复原图 delete [] verList; verList = tmp; p = beg; while (p != NULL) { cout << verList[p->nodeNum].ver << '\t'; pre = p; p = p->next; delete pre; } cout << endl; } //拓扑排序 void topologySort() const { //计算入度 int *inDegree = new int[vers]; memset(inDegree, 0, vers * sizeof(int)); for (int i = 0; i < vers; ++i){ EdgeNode *p = verList[i].head; while (p != NULL) { ++inDegree[p->end]; p = p->next; } } //入度为0的放入队列 queue<int> q; for (int i = 0; i < vers; ++i){ if (inDegree[i] == 0) q.push(i); } while (!q.empty()) { int v = q.front(); q.pop(); cout << verList[v].ver << '\t'; //入度减1, 为0的放入队列 EdgeNode *p = verList[v].head; while (p != NULL) { --inDegree[p->end]; if (inDegree[p->end] == 0) { q.push(p->end); } p = p->next; } } cout << endl; } //kruskal算法求最小生成树( 时间复杂度O(|E|log|E|) ) void kruskal() const { priority_queue<Edge, deque<Edge>, greater<Edge>> pq; //最小堆 //priority_queue<Edge, deque<Edge>, compEdgeGreater> pq; //最小堆 //priority_queue<Edge> pq; //默认最大堆 DisjointSet ds(vers); //所有边放入优先级队列 for (int i = 0; i < vers; ++i) { EdgeNode *p = verList[i].head; while (p != NULL) { if (i < p->end) { //只添加一次 Edge edge(i, p->end, p->weight); pq.push(edge); } p = p->next; } } //合并生成最小生成树 int count = 0; while (count < vers - 1) { Edge edge = pq.top(); pq.pop(); int u = ds.find(edge.beg); int v = ds.find(edge.end); if (u != v) { ++count; ds.unionTwoSet(u, v); cout << "(" << verList[edge.beg].ver << "," << verList[edge.end].ver << ")\t"; } } cout << endl; } //prim算法求最小生成树( 时间复杂度O(|V^2|) ) void prim(TypeOfEdge noEdge) const { //顶点集合V, 最小生成树结点集合U, 剩余结点V-U bool *flag = new bool[vers]; //结点在U中为true TypeOfEdge *lowCost = new TypeOfEdge[vers]; //U中结点到结点i的最小权值, 当i在U中时lowCost为noEdge, 当i在V-U中时lowCost为有限值 int *startNode = new int[vers]; //U中结点startNode[i]到结点i的权值是lowCost[i] for (int i = 0; i < vers; ++i) { flag[i] = false; lowCost[i] = noEdge; } int start = 0; //起始点 int current = start; //current是即将加入到U中的结点 for (int i = 1; i < vers; ++i) { EdgeNode *p = verList[current].head; while (p != NULL) { if (!flag[p->end] && p->weight < lowCost[p->end]) { //结点p->end不在U中, 并且结点p->end到结点current的距离小于结点p->end到U中已有点的最小距离 lowCost[p->end] = p->weight; startNode[p->end] = current; } p = p->next; } //current加入U flag[current] = true; //寻找V-U中到V-U的最小距离点 TypeOfEdge min = noEdge; bool tflag = false; for (int j = 0; j < vers; ++j) { if (lowCost[j] < min) { min = lowCost[j]; #if 1 current = j; //取V-U中到U的最小距离点作为下一个计算点 #else if (!tflag) { tflag = true; current = j; //在V-U中随意取一个点,与上面的方法结果一致 } #endif } } cout << "(" << verList[startNode[current]].ver << "," << verList[current].ver << ")\t"; lowCost[current] = noEdge; } cout << endl; delete [] flag; delete [] lowCost; delete [] startNode; } //非加权图的单源最短路径( bfs算法, 时间复杂度为|V|和|E|中的较小者, 即O(|V| + |E|) ) void unweightedShortDistance(TypeOfVer start, TypeOfEdge noEdge) const { //找到起始点序号 int iStart = 0; for (iStart = 0; iStart < vers; ++iStart) { if (verList[iStart].ver == start) break; } if (iStart == vers) return; TypeOfEdge *distance = new TypeOfEdge[vers]; int *prev = new int[vers]; for (int i = 0; i < vers; ++i) { distance[i] = noEdge; } distance[iStart] = 0; prev[iStart] = iStart; queue<int> q; q.push(iStart); while (!q.empty()) { int u = q.front(); q.pop(); EdgeNode *p = verList[u].head; while (p != NULL) { if (distance[p->end] == noEdge) { distance[p->end] = distance[u] + 1; prev[p->end] = u; q.push(p->end); } p = p->next; } } for (int i = 0; i < vers; ++i) { cout << "the path from " << start << " to " << verList[i].ver << ": "; printPath(iStart, i, prev); cout << endl; } cout << endl; delete [] distance; delete [] prev; } //加权图的单源最短路径(dijkstra算法与prim算法有些类似, 时间复杂度O(|V^2|) ) void dijkstra(TypeOfVer start, TypeOfEdge noEdge) const { //找到起始点序号 int iStart = 0; for (iStart = 0; iStart < vers; ++iStart) { if (verList[iStart].ver == start) break; } if (iStart == vers) return; //顶点集合V, 已经找到最短路径的顶点集合U, 剩余结点V-U TypeOfEdge *distance = new TypeOfEdge[vers]; //结点i到起始点的最短距离 bool *konwn = new bool[vers]; //结点在U中为true int *prev = new int[vers]; //结点i的前继结点 for (int i = 0; i < vers; ++i) { distance[i] = noEdge; konwn[i] = false; } distance[iStart] = 0; prev[iStart] = iStart; int current = iStart; for (int i = 1; i < vers; ++i) { //寻找V-U中到U中的最小距离点 TypeOfEdge min = noEdge; for (int j = 0; j < vers; ++j) { if (!konwn[j] && distance[j] < min) { min = distance[j]; current = j; } } konwn[current] = true; EdgeNode *p = verList[current].head; while (p != NULL) { if (!konwn[p->end] && min + p->weight < distance[p->end]) { distance[p->end] = min + p->weight; prev[p->end] = current; } p = p->next; } } for (int i = 0; i < vers; ++i) { cout << "the path from " << start << " to " << verList[i].ver << ": "; printPath(iStart, i, prev); cout << "\twith length: " << distance[i] << endl; } cout << endl; delete [] distance; delete [] prev; delete [] konwn; } //带负权值图的单源最短路径(可以有环, 但不能有负环, 时间复杂度O(|V||E|) ) void weightedNegative(TypeOfVer start, TypeOfEdge noEdge) const { //找到起始点序号 int iStart = 0; for (iStart = 0; iStart < vers; ++iStart) { if (verList[iStart].ver == start) break; } if (iStart == vers) return; TypeOfEdge *distance = new TypeOfEdge[vers]; int *prev = new int[vers]; for (int i = 0; i < vers; ++i) { distance[i] = noEdge; } distance[iStart] = 0; prev[iStart] = iStart; queue<int> q; q.push(iStart); while (!q.empty()) { int u = q.front(); q.pop(); EdgeNode *p = verList[u].head; while (p != NULL) { if (distance[u] + p->weight < distance[p->end]) { distance[p->end] = distance[u] + p->weight; prev[p->end] = u; q.push(p->end); } p = p->next; } } for (int i = 0; i < vers; ++i) { cout << "the path from " << start << " to " << verList[i].ver << ": "; printPath(iStart, i, prev); cout << "\twith length: " << distance[i] << endl; } cout << endl; delete [] distance; delete [] prev; } private: struct EdgeNode { int end; TypeOfEdge weight; EdgeNode *next; EdgeNode(int e, TypeOfEdge w, EdgeNode *n = NULL):end(e), weight(w), next(n) {} }; struct VerNode { TypeOfVer ver; EdgeNode *head; VerNode(EdgeNode *h = NULL):head(h){} VerNode(TypeOfVer v, EdgeNode *h = NULL):ver(v), head(h){} }; VerNode *verList; bool isWeighted; bool isDirected; void dfsCore(int start, bool *visited) const { cout << verList[start].ver << '\t'; visited[start] = true; EdgeNode *p = verList[start].head; while (p != NULL) { if (!visited[p->end]) dfsCore(p->end, visited); p = p->next; } } struct EulerNode { int nodeNum; EulerNode *next; EulerNode(int num, EulerNode *n = NULL):nodeNum(num), next(n) {} }; VerNode *clone() const { VerNode *tmp = new VerNode[vers]; for (int i = 0; i < vers; ++i){ tmp[i].ver = verList[i].ver; EdgeNode *p = verList[i].head; while (p != NULL) { tmp[i].head = new EdgeNode(p->end, p->weight, tmp[i].head); p = p->next; } } return tmp; } void eulerCircuitCore(int start, EulerNode *&beg, EulerNode *&end) { beg = end = new EulerNode(start); while (verList[start].head != NULL) { int nextNodeNum = verList[start].head->end; remove(start, nextNodeNum); //remove(nextNodeNum, start); end->next = new EulerNode(nextNodeNum); end = end->next; start = nextNodeNum; } } struct Edge { int beg, end; TypeOfEdge weight; Edge(int b, int e, TypeOfEdge w):beg(b), end(e),weight(w) {} bool operator>(const Edge &right) const { return weight > right.weight; } }; struct compEdgeGreater { bool operator()(Edge first, Edge second) { return first.weight > second.weight; } }; void printPath(int start, int end, int *prev) const { if (start == end) { cout << verList[start].ver; return; } printPath(start, prev[end], prev); cout << "-" << verList[end].ver; } }; //有向加权图的邻接矩阵实现 //作为无权图使用时,可将weight置1,权值一样 //作为无向图使用时,插入和删除时需将两个方向的边均插入或删除,修改weight时同样 template <class TypeOfVer, class TypeOfEdge> class AdjMatrixGraph : public Graph<TypeOfEdge>{ public: //这里为了方便,所有成员函数写成内联函数的形式 AdjMatrixGraph(int v, const TypeOfVer *d, TypeOfEdge noEdgeFlag, bool isWeightedFlag, bool isDirectedFlag) { vers = v; edges = 0; noEdge = noEdgeFlag; isWeighted = isWeightedFlag; isDirected = isDirectedFlag; ver = new TypeOfVer[vers]; for (int i = 0; i < vers; ++i) { ver[i] = d[i]; } edge = new TypeOfEdge *[vers]; for (int i = 0; i < vers; ++i) { edge[i] = new TypeOfEdge[vers]; for (int j = 0; j < vers; ++j) { edge[i][j] = noEdge; } edge[i][i] = 0; } } ~AdjMatrixGraph() { delete [] ver; for (int i = 0; i < vers; ++i) { delete [] edge[i]; } delete [] edge; } bool insert(int u, int v, TypeOfEdge w) { if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1) return false; if (exist(u, v)) return false; edge[u][v] = w; if (!isDirected) edge[v][u] = w; ++edges; return true; } bool remove(int u, int v) { if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1) return false; if (!exist(u, v)) return false; edge[u][v] = noEdge; if (!isDirected) edge[v][u] = noEdge; --edges; return true; } bool modify(int u, int v, TypeOfEdge w) { if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1) return false; if (!exist(u, v)) return false; edge[u][v] = w; if (!isDirected) edge[v][u] = w; return true; } bool exist(int u, int v) const { if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1) return false; if (edge[u][v] == noEdge) return false; return true; } //所有顶点对的最短路径( 时间复杂度O(|V^3|) ) void floyd() const { TypeOfEdge **d = new TypeOfEdge *[vers]; int **prev = new int *[vers]; for (int i = 0; i < vers; ++i) { d[i] = new TypeOfEdge[vers]; prev[i] = new int[vers]; for (int j = 0; j < vers; ++j) { d[i][j] = edge[i][j]; prev[i][j] = (edge[i][j] != noEdge) ? i : -1; } } for (int k = 0; k < vers; ++k) { for (int i = 0; i < vers; ++i) { for (int j = 0; j < vers; ++j) { if (d[i][k] + d[k][j] < d[i][j]) { d[i][j] = d[i][k] + d[k][j]; prev[i][j] = prev[k][j]; } } } } for (int i = 0; i < vers; ++i) { for (int j = 0; j < vers; ++j) { cout << "the path from " << ver[i] << " to " << ver[j] << ": "; printPath(i, j, prev); cout << "\twith length: " << d[i][j]<< endl; } } //cout << "最短路径" << endl; //for (int i = 0; i < vers; ++i) { // for (int j = 0; j < vers; ++j) { // cout << prev[i][j] << "\t"; // } // cout << endl; //} //cout << "长度" << endl; //for (int i = 0; i < vers; ++i) { // for (int j = 0; j < vers; ++j) { // cout << d[i][j] << "\t"; // } // cout << endl; //} cout << endl; delete [] d; delete [] prev; } private: TypeOfEdge **edge; TypeOfVer *ver; TypeOfEdge noEdge; bool isWeighted; bool isDirected; void printPath(int start, int end, int **prev) const { if (start == end) { cout << ver[start]; return; } printPath(start, prev[start][end], prev); cout << "-" << ver[end]; } }; //不相交集(并查集) class DisjointSet { public: DisjointSet(int n) { size = n; parent = new int[n]; for (int i = 0; i < n; ++i) { parent[i] = -1; } } ~DisjointSet(){ delete [] parent; } int find(int x) { if (parent[x] < 0) return x; return parent[x] = find(parent[x]); } void unionTwoSet(int root1, int root2){ if (root1 == root2) return; if (parent[root1] > parent[root2]) { //root1规模小 parent[root2] += parent[root1]; parent[root1] = root2; } else{ parent[root1] += parent[root2]; parent[root2] = root1; } } private: int size; int *parent; }; #endif
main.cpp
#include "graph.h" #include <iostream> using namespace std; int main() { //有向图的遍历 cout << "有向图的遍历:" << endl; AdjListGraph<char, int> g(7, "0123456", true, true); //adjListGraph<char, int> g(7, "1234567", true, true); //adjListGraph<char, int> g(7, "abcdefg", true, true); g.insert(4, 5, 1); g.insert(4, 6, 1); g.insert(6, 5, 1); g.insert(5, 1, 1); g.insert(6, 3, 1); g.insert(1, 3, 1); g.insert(0, 1, 1); g.insert(3, 2, 1); g.insert(1, 2, 1); g.insert(3, 0, 1); g.insert(2, 0, 1); g.dfs(); cout << endl; g.dfs(4); cout << endl; g.bfs(); cout << endl; g.bfs(4); cout << endl; //无向图的欧拉回路 cout << "无向图的欧拉回路:" << endl; AdjListGraph<char, int> eulerGraph(6, "012345", true, false); eulerGraph.insert(0, 1, 1); eulerGraph.insert(0, 2, 1); eulerGraph.insert(1, 2, 1); eulerGraph.insert(2, 3, 1); eulerGraph.insert(1, 4, 1); eulerGraph.insert(1, 3, 1); eulerGraph.insert(2, 4, 1); eulerGraph.insert(3, 4, 1); eulerGraph.insert(3, 5, 1); eulerGraph.insert(4, 5, 1); eulerGraph.eulerCircuit('5'); //有向无环图的拓扑排序 cout << "有向无环图的拓扑排序:" << endl; AdjListGraph<char, int> topologyGraph(7, "0123456", true, true); topologyGraph.insert(0, 1, 1); topologyGraph.insert(0, 2, 1); topologyGraph.insert(1, 3, 1); topologyGraph.insert(1, 4, 1); topologyGraph.insert(1, 5, 1); topologyGraph.insert(2, 4, 1); topologyGraph.insert(2, 6, 1); topologyGraph.insert(4, 5, 1); topologyGraph.insert(4, 6, 1); topologyGraph.insert(5, 3, 1); topologyGraph.topologySort(); //无向图的最小生成树 cout << "最小生成树:" << endl; //AdjListGraph<char, int> minimumSpanningTree(6, "012345", true, false); AdjListGraph<char, int> minimumSpanningTree(6, "123456", true, false); minimumSpanningTree.insert(0, 3, 5); minimumSpanningTree.insert(3, 5, 2); minimumSpanningTree.insert(4, 5, 6); minimumSpanningTree.insert(1, 4, 3); minimumSpanningTree.insert(0, 1, 6); minimumSpanningTree.insert(0, 2, 1); minimumSpanningTree.insert(1, 2, 5); minimumSpanningTree.insert(2, 3, 5); minimumSpanningTree.insert(2, 4, 6); minimumSpanningTree.insert(2, 5, 4); minimumSpanningTree.kruskal(); minimumSpanningTree.prim(INT_MAX); //有向图的单源最短路径 cout << "单源最短路径:" << endl; AdjListGraph<char, int> singleSourceShortestPath(7, "0123456", true, true); singleSourceShortestPath.insert(0, 1, 2); singleSourceShortestPath.insert(1, 4, 10); singleSourceShortestPath.insert(4, 6, 6); singleSourceShortestPath.insert(6, 5, 1); singleSourceShortestPath.insert(2, 0, 4); singleSourceShortestPath.insert(2, 5, 5); singleSourceShortestPath.insert(0, 3, 1); singleSourceShortestPath.insert(1, 3, 3); singleSourceShortestPath.insert(3, 2, 2); singleSourceShortestPath.insert(3, 4, 2); singleSourceShortestPath.insert(3, 5, 8); singleSourceShortestPath.insert(3, 6, 4); cout << "非加权图" << endl; singleSourceShortestPath.unweightedShortDistance('2', INT_MAX); cout << "加权图" << endl; //singleSourceShortestPath.dijkstra('1', INT_MAX); singleSourceShortestPath.dijkstra('2', INT_MAX); //有向带负权值图的单源最短路径 AdjListGraph<char, int> singleSourceShortestPathWeightedNegative(7, "0123456", true, true); singleSourceShortestPathWeightedNegative.insert(0, 1, 2); singleSourceShortestPathWeightedNegative.insert(1, 4, 10); singleSourceShortestPathWeightedNegative.insert(4, 6, 6); singleSourceShortestPathWeightedNegative.insert(6, 5, 1); singleSourceShortestPathWeightedNegative.insert(2, 0, 4); singleSourceShortestPathWeightedNegative.insert(2, 5, 3); singleSourceShortestPathWeightedNegative.insert(0, 3, 1); singleSourceShortestPathWeightedNegative.insert(1, 3, 3); singleSourceShortestPathWeightedNegative.insert(3, 2, 2); singleSourceShortestPathWeightedNegative.insert(3, 4, 2); singleSourceShortestPathWeightedNegative.insert(3, 5, -8); singleSourceShortestPathWeightedNegative.insert(3, 6, 4); cout << "带负权值图" << endl; singleSourceShortestPathWeightedNegative.weightedNegative('2', INT_MAX); //有向图所有顶点对的最短路径 cout << "所有顶点对的最短路径:" << endl; AdjMatrixGraph<char, int> allVertexPairShortestPath(3, "012", INT_MAX, true, true); allVertexPairShortestPath.insert(0, 1, 8); allVertexPairShortestPath.insert(1, 0, 3); allVertexPairShortestPath.insert(0, 2, 5); allVertexPairShortestPath.insert(2, 0, 6); allVertexPairShortestPath.insert(2, 1, 2); allVertexPairShortestPath.floyd(); int ttt = 0; return 0; }
标签:
原文地址:http://blog.csdn.net/richrdbird/article/details/51335357