标签:
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。
template <typename T, typename E> void graph_mtx<T, E>::topological_sort() { int num = this->get_numvertices(); assert(num != -1); int *count = new int[num]; assert(count != nullptr); for(int i=0; i<num; ++i) for(int j=0; j<num; ++j){ if(edge[i][j] != 0 && edge[i][j] != MAX_COST) count[j]++; //统计入度 } int top = -1; for(int i=0; i<num; ++i) if(count[i] == 0){ //利用数组模拟栈 count[i] = top; //相当于压栈,存储之前位置 top = i; //存储当前位置 } for(int i=0; i<num; ++i){ if(top == -1) //如果为-1,说明有环存在,回到了起始位置 return ; int index_tmp = top; top = count[top]; //取栈顶元素 cout << get_vertex_symbol(index_tmp) << " "; //输出栈顶元素 int neighbor_index = get_firstneighbor(get_vertex_symbol(index_tmp)); while(neighbor_index != -1){ if(--count[neighbor_index] == 0){ //如果入度减为0,入栈 count[neighbor_index] = top; top = neighbor_index; } neighbor_index = get_nextneighbor(get_vertex_symbol(index_tmp), get_vertex_symbol(neighbor_index)); } } delete []count; }
template <typename T, typename E> void graph_mtx<T, E>::critical_path(const T& vert) { int num = this->get_numvertices(); int *early_start = new int[num]; //最早开始时间数组 int *late_start = new int[num]; //最晚开始时间数组 assert(early_start != nullptr && late_start != nullptr); int index = get_vertex_index(vert); assert(index != -1); for(int i=0; i<num; ++i) early_start[i] = 0; //初始化为0 for(int i=0; i<num; ++i){ int neighbor_index = get_firstneighbor(get_vertex_symbol(i)); while(neighbor_index != -1){ int weight = edge[i][neighbor_index]; if(early_start[i]+weight > early_start[neighbor_index]) //如果某点最早开始时间加上某点到其邻接点的权值大于该邻接点之前的权值,说明新路径长,更新该邻接点权值 early_start[neighbor_index] = early_start[i]+weight; neighbor_index = get_nextneighbor(get_vertex_symbol(i), get_vertex_symbol(neighbor_index)); } } for(int i=0; i<num; ++i) cout << early_start[i] << " "; //打印最早开始时间 cout << endl; for(int i=0; i<num; ++i) late_start[i] = MAX_COST; //初始化为无穷时间 late_start[num-1] = early_start[num-1]; //汇点的最早开始时间和最晚开始时间相同 for(int i=num-2; i>=0; --i){ //除开汇点,从num-2开始 int neighbor_index = get_firstneighbor(get_vertex_symbol(i)); while(neighbor_index != -1){ int weight = edge[i][neighbor_index]; if(late_start[neighbor_index]-weight < late_start[i])//某点的邻接点的最晚开始时间减去权值小于某点之前的最晚开始时间,说明现有从后往前的路径长,则更新为最晚开始时间 late_start[i] = late_start[neighbor_index]-weight; neighbor_index = get_nextneighbor(get_vertex_symbol(i), get_vertex_symbol(neighbor_index)); } } for(int i=0; i<num; ++i) cout << late_start[i] << " "; //打印最晚开始时间 cout << endl; for(int i=0; i<num; ++i) if(early_start[i] == late_start[i]) cout << get_vertex_symbol(i) << " "; //若最早开始时间和最晚开始时间相等,则为关键路径 delete []early_start; delete []late_start; }
template <typename T, typename E> void graph_mtx<T, E>::shortest_path(const T& vert) { int num = this->get_numvertices(); int *dist = new int[num]; int *path = new int[num]; int *lable_incorporated = new int[num]; assert(dist != nullptr && path != nullptr && lable_incorporated != nullptr); int index = get_vertex_index(vert); assert(index != -1); for(int i=0; i<num; ++i){ lable_incorporated[i] = false; dist[i] = edge[index][i]; if(edge[index][i] != 0 && dist[i] < MAX_COST) path[i] = index; //如果从vert可以到达该点,路径默认为vert,表明到达该点的上一个顶点为vert else path[i] = -1; //自身及不可达设为-1 } lable_incorporated[index] = true; //首先将起始点vert并入 for(int i=0; i<num-1; ++i){ int min = MAX_COST; int min_index = -1; for(int j=0; j<num; ++j){ if(!lable_incorporated[j] && dist[j] < min){ //在未并入的顶点中找到最短可达的花费最小的顶点 min = dist[j]; min_index = j; } } lable_incorporated[min_index] = true; //并入该顶点 for(int j=0; j<num; ++j){ int weight = edge[min_index][j]; if(!lable_incorporated[j] && weight < MAX_COST //此处注意,如果不加weight<MAX_COST,那么dist[]数组重元素加上MAX_COST数据溢出,编译器默认为赋值,这就导致dist[min_index]+weight永远小于dist[j],出现错误 && dist[min_index]+weight < dist[j]){ //weight<MAX_COST dist[j] = dist[min_index]+weight; //更新路径 path[j] = min_index; } } } cout << "dist:" << " "; for(int i=0; i<num; ++i) cout << setw(3) << dist[i] << " "; cout <<endl; cout << "path:" << " "; for(int i=0; i<num; ++i) cout << setw(3) << path[i] << " "; delete []dist; delete []path; }
#ifndef _GRAPH_H #define _GRAPH_H #include <iostream> #include <string.h> #include <assert.h> #include <queue> #include <iomanip> using namespace::std; #define MAX_COST 0x7FFFFFFF /////////////////////////////////////////////////////////////////////////////////////////// //通用图结构 template <typename T, typename E> class graph{ public: bool is_empty()const; bool is_full()const; int get_numvertices()const; //当前顶点数 int get_numedges()const; //当前边数 public: virtual bool insert_vertex(const T&) = 0; //插入顶点 virtual bool insert_edge(const T&, const T&, E) = 0; //插入边 virtual int get_firstneighbor(const T&)const = 0; //得到第一个邻接顶点 virtual int get_nextneighbor(const T&, const T&)const = 0; //某邻接顶点的下一个邻接顶点 virtual void print_graph()const = 0; virtual int get_vertex_index(const T&)const = 0; //得到顶点序号 protected: static const int VERTICES_DEFAULT_SIZE = 10; //默认图顶点数 int max_vertices; int num_vertices; int num_edges; }; template <typename T, typename E> bool graph<T, E>::is_empty()const { return num_edges == 0; } template <typename T, typename E> bool graph<T, E>::is_full()const { return num_vertices >= max_vertices || num_edges >= max_vertices*(max_vertices-1)/2; //判满,分为顶点满和边满 } template <typename T, typename E> int graph<T, E>::get_numvertices()const { return num_vertices; } template <typename T, typename E> int graph<T, E>::get_numedges()const { return num_edges; } /////////////////////////////////////////////////////////////////////////////////////////// #define VERTICES_DEFAULT_SIZE graph<T, E>::VERTICES_DEFAULT_SIZE #define num_vertices graph<T, E>::num_vertices #define num_edges graph<T, E>::num_edges #define max_vertices graph<T, E>::max_vertices /////////////////////////////////////////////////////////////////////////////////////////// #endif /*graph.h*/
#pragma once #include "graph.h" //图的邻接矩阵表示法 template <typename T, typename E> class graph_mtx : public graph<T, E>{ public: graph_mtx(int); ~graph_mtx(); public: bool insert_vertex(const T&); bool insert_edge(const T&, const T&, E); int get_firstneighbor(const T&)const; int get_nextneighbor(const T&, const T&)const; int get_vertex_index(const T&)const; T& get_vertex_symbol(const int)const; void print_graph()const; void topological_sort(); void shortest_path(const T&); void critical_path(const T&); private: T* vertices_list; //顶点线性表 E **edge; //内部矩阵 }; template <typename T, typename E> graph_mtx<T, E>::graph_mtx(int sz = VERTICES_DEFAULT_SIZE) { max_vertices = sz > VERTICES_DEFAULT_SIZE ? sz : VERTICES_DEFAULT_SIZE; vertices_list = new T[max_vertices]; edge = new int*[max_vertices]; //动态申请二维数组 for(int i=0; i<max_vertices; ++i){ edge[i] = new int[max_vertices]; } for(int i=0; i<max_vertices; ++i) for(int j=0; j<max_vertices; ++j){ if(i != j) edge[i][j] = MAX_COST; else edge[i][j] = 0; } num_vertices = 0; num_edges = 0; } template <typename T, typename E> graph_mtx<T, E>::~graph_mtx() { for(int i=0; i<max_vertices; ++i) delete []edge[i]; //分别析构,再总析构 delete edge; delete []vertices_list; } template <typename T, typename E> bool graph_mtx<T, E>::insert_vertex(const T& vert) { if(this->is_full()) //派生类函数调用父类函数,用this或加作用域 return false; vertices_list[num_vertices++] = vert; return true; } template <typename T, typename E> bool graph_mtx<T, E>::insert_edge(const T& vert1, const T& vert2, E cost = MAX_COST) { if(this->is_full()) //判满 return false; int index_v1 = get_vertex_index(vert1); //得到顶点序号 int index_v2 = get_vertex_index(vert2); if(index_v1 == -1 || index_v2 == -1 ) return false; edge[index_v1][index_v2] = cost; //无向图 ++num_edges; return true; } template <typename T, typename E> int graph_mtx<T, E>::get_firstneighbor(const T& vert)const { int index = get_vertex_index(vert); if(index != -1){ for(int i=0; i<num_vertices; ++i){ if(edge[index][i] != 0 && edge[index][i] != MAX_COST) return i; } } return -1; } template <typename T, typename E> int graph_mtx<T, E>::get_nextneighbor(const T& vert1, const T& vert2)const { int index_v1 = get_vertex_index(vert1); int index_v2 = get_vertex_index(vert2); if(index_v1 != -1 && index_v2 != -1){ for(int i=index_v2+1; i<num_vertices; ++i){ if(edge[index_v1][i] != 0 && edge[index_v1][i] != MAX_COST) return i; } } return -1; } template <typename T, typename E> int graph_mtx<T, E>::get_vertex_index(const T& vert)const { for(int i=0; i<num_vertices; ++i){ if(vertices_list[i] == vert) return i; } return -1; } template <typename T, typename E> T& graph_mtx<T, E>::get_vertex_symbol(const int index)const { assert(index >= 0 && index < this->get_numvertices()); return vertices_list[index]; } template <typename T, typename E> void graph_mtx<T, E>::print_graph()const { if(this->is_empty()){ cout << "nil graph" << endl; //空图输出nil return; } for(int i=0; i<num_vertices; ++i){ cout << vertices_list[i] << " "; } cout << endl; for(int i=0; i<num_vertices; ++i){ for(int j=0; j<num_vertices; ++j){ if(edge[i][j] != MAX_COST) cout << edge[i][j] << " "; else cout << '@' << " "; } cout << vertices_list[i] << endl; } } template <typename T, typename E> void graph_mtx<T, E>::topological_sort() { int num = this->get_numvertices(); assert(num != -1); int *count = new int[num]; assert(count != nullptr); for(int i=0; i<num; ++i) for(int j=0; j<num; ++j){ if(edge[i][j] != 0 && edge[i][j] != MAX_COST) count[j]++; } int top = -1; for(int i=0; i<num; ++i) if(count[i] == 0){ count[i] = top; top = i; } for(int i=0; i<num; ++i){ if(top == -1) return ; int index_tmp = top; top = count[top]; cout << get_vertex_symbol(index_tmp) << " "; int neighbor_index = get_firstneighbor(get_vertex_symbol(index_tmp)); while(neighbor_index != -1){ if(--count[neighbor_index] == 0){ count[neighbor_index] = top; top = neighbor_index; } neighbor_index = get_nextneighbor(get_vertex_symbol(index_tmp), get_vertex_symbol(neighbor_index)); } } delete []count; } template <typename T, typename E> void graph_mtx<T, E>::shortest_path(const T& vert) { int num = this->get_numvertices(); int *dist = new int[num]; int *path = new int[num]; int *lable_incorporated = new int[num]; assert(dist != nullptr && path != nullptr && lable_incorporated != nullptr); int index = get_vertex_index(vert); assert(index != -1); for(int i=0; i<num; ++i){ lable_incorporated[i] = false; dist[i] = edge[index][i]; if(edge[index][i] != 0 && dist[i] < MAX_COST) path[i] = index; else path[i] = -1; } lable_incorporated[index] = true; for(int i=0; i<num-1; ++i){ int min = MAX_COST; int min_index = -1; for(int j=0; j<num; ++j){ if(!lable_incorporated[j] && dist[j] < min){ min = dist[j]; min_index = j; } } lable_incorporated[min_index] = true; for(int j=0; j<num; ++j){ int weight = edge[min_index][j]; if(!lable_incorporated[j] && weight < MAX_COST && dist[min_index]+weight < dist[j]){ //weight<MAX_COST dist[j] = dist[min_index]+weight; path[j] = min_index; } } } cout << "dist:" << " "; for(int i=0; i<num; ++i) cout << setw(3) << dist[i] << " "; cout <<endl; cout << "path:" << " "; for(int i=0; i<num; ++i) cout << setw(3) << path[i] << " "; delete []dist; delete []path; } template <typename T, typename E> void graph_mtx<T, E>::critical_path(const T& vert) { int num = this->get_numvertices(); int *early_start = new int[num]; int *late_start = new int[num]; assert(early_start != nullptr && late_start != nullptr); int index = get_vertex_index(vert); assert(index != -1); for(int i=0; i<num; ++i) early_start[i] = 0; for(int i=0; i<num; ++i){ int neighbor_index = get_firstneighbor(get_vertex_symbol(i)); while(neighbor_index != -1){ int weight = edge[i][neighbor_index]; if(early_start[i]+weight > early_start[neighbor_index]) early_start[neighbor_index] = early_start[i]+weight; neighbor_index = get_nextneighbor(get_vertex_symbol(i), get_vertex_symbol(neighbor_index)); } } for(int i=0; i<num; ++i) cout << early_start[i] << " "; cout << endl; for(int i=0; i<num; ++i) late_start[i] = MAX_COST; late_start[num-1] = early_start[num-1]; for(int i=num-2; i>=0; --i){ int neighbor_index = get_firstneighbor(get_vertex_symbol(i)); while(neighbor_index != -1){ int weight = edge[i][neighbor_index]; if(late_start[neighbor_index]-weight < late_start[i]) late_start[i] = late_start[neighbor_index]-weight; neighbor_index = get_nextneighbor(get_vertex_symbol(i), get_vertex_symbol(neighbor_index)); } } for(int i=0; i<num; ++i) cout << late_start[i] << " "; cout << endl; for(int i=0; i<num; ++i) if(early_start[i] == late_start[i]) cout << get_vertex_symbol(i) << " "; delete []early_start; delete []late_start; }
#include "graph.h" #include "graph_mtx.h" int main() { graph_mtx<char, int> gm; //critical_path gm.insert_vertex('A'); gm.insert_vertex('B'); gm.insert_vertex('C'); gm.insert_vertex('D'); gm.insert_vertex('E'); gm.insert_vertex('F'); gm.insert_vertex('G'); gm.insert_vertex('H'); gm.insert_vertex('I'); gm.insert_edge('A', 'B', 6); gm.insert_edge('A', 'C', 4); gm.insert_edge('A', 'D', 5); gm.insert_edge('B', 'E', 1); gm.insert_edge('C', 'E', 1); gm.insert_edge('D', 'F', 2); gm.insert_edge('E', 'G', 9); gm.insert_edge('E', 'H', 7); gm.insert_edge('G', 'I', 2); gm.insert_edge('H', 'I', 5); gm.insert_edge('F', 'H', 4); gm.critical_path('A'); cout << endl; #if 0 //shortest_path gm.insert_vertex('A'); gm.insert_vertex('B'); gm.insert_vertex('C'); gm.insert_vertex('D'); gm.insert_vertex('E'); gm.insert_edge('A', 'B', 10); gm.insert_edge('A', 'D', 30); gm.insert_edge('A', 'E', 100); gm.insert_edge('B', 'C', 50); gm.insert_edge('C', 'E', 10); gm.insert_edge('D', 'C', 20); gm.insert_edge('D', 'E', 60); cout << "shortest_path:" << endl; gm.shortest_path('A'); cout << endl; #endif #if 0 //topological_sort gm.insert_vertex('A'); gm.insert_vertex('B'); gm.insert_vertex('C'); gm.insert_vertex('D'); gm.insert_vertex('E'); gm.insert_vertex('F'); gm.insert_edge('A', 'B', 6); gm.insert_edge('A', 'C', 1); gm.insert_edge('A', 'D', 5); gm.insert_edge('C', 'B', 5); gm.insert_edge('C', 'E', 3); gm.insert_edge('D', 'E', 5); gm.insert_edge('F', 'E', 4); gm.insert_edge('F', 'D', 2); cout << "topological_sort:" << endl; gm.topological_sort(); cout << endl; #endif return 0; }
标签:
原文地址:http://blog.csdn.net/freeelinux/article/details/52260785