基于邻接表的拓扑排序实现

  上一篇博客实现了图的基本操作(使用邻接表),包括图的创建、输出、遍历等,这次来实现一下拓扑排序。拓扑排序基本原理可以参考以前转载的一篇博客

http://www.cnblogs.com/zhangbaochong/p/5406159.html

  由于代码比较简单,就直接贴出来了

  1 #include <queue>
  2 #include <vector>
  3 #include <stack>
  4 #include <iostream>
  5 using namespace std;
  6
  7
  8 enum GraphType
  9 {
 10     UNDIR_UNWEIGHT_GRAPH,        //无向无权图
 11     UNDIR_WEIGHT_GRAPH,            //无向带权图
 12     DIR_UNWEIGHT_GRAPH,            //有向无权图
 13     DIR_WEIGHT_GRAPH            //有向带权图
 14 };
 15
 16 //结点颜色代表遍历情况
 17 enum ColorType
 18 {
 19     WHITE,    //未访问
 20     GRAY,    //正在访问,邻接点还没访问完
 21     BLACK    //访问完毕
 22 };
 23
 24 template<typename VertexType, typename InfoType>
 25 class Graph
 26 {
 27 public:
 28     Graph(int vertexNum, GraphType type) :m_vertexNum(vertexNum), m_type(type), m_arcNum(0)
 29     {
 30         for (int i = 0; i < MAX_VERTEX_NUM; ++i)
 31         {
 32             m_vertices[i].firstArc = nullptr;
 33         }
 34     }
 35
 36     void Create()
 37     {
 38         CreateDirUnweightGraph();
 39     }
 40
 41
 42     //输出图的信息
 43     void Display()
 44     {
 45         for (int i = 0; i < m_vertexNum; ++i)
 46         {
 47             cout << "第" << i + 1 << "个结点为" << m_vertices[i].data << " 邻接表为:";
 48             ArcNode* node = m_vertices[i].firstArc;
 49             while (node)
 50             {
 51                 cout << "->" << m_vertices[node->vertexIndex].data << "(" << node->info << ")";
 52                 node = node->next;
 53             }
 54             cout << endl;
 55         }
 56     }
 57
 58     //拓扑排序
 59     void TopologicalSort()
 60     {
 61         cout << "拓扑排序为:";
 62         CountInDegree();
 63         stack<Vertex> s;
 64         //把所有入度为0的结点入栈
 65         for (int i = 0; i < m_vertexNum; ++i)
 66         {
 67             if (m_inDegreeArray[i] == 0)
 68                 s.push(m_vertices[i]);
 69         }
 70         int count = 0;//输出结点计数,用于判断有没有环
 71         while (!s.empty())
 72         {
 73             Vertex v = s.top();
 74             s.pop();
 75             cout << v.data << "->";
 76             ++count;
 77             ArcNode* node = v.firstArc;
 78             while (node)
 79             {
 80                 //从图中删除结点v,v指向的结点入度-1
 81                 //结点 入度为0加入栈中
 82                 if (--m_inDegreeArray[node->vertexIndex] == 0)
 83                     s.push(m_vertices[node->vertexIndex]);
 84                 node = node->next;
 85             }
 86         }
 87         if (count < m_vertexNum)
 88             cout << "图中存在环!" << endl;
 89     }
 90 private:
 91     struct ArcNode
 92     {
 93         int vertexIndex;        //该弧指向的顶点位置
 94         struct ArcNode* next;    //指向下一个弧
 95         InfoType info;            //该弧的相关信息,如权重等
 96     };
 97
 98     struct Vertex
 99     {
100         VertexType data;    //顶点信息
101         ArcNode* firstArc;    //指向第一条依附该节点弧的指针
102         ColorType color;    //访问情况
103     };
104
105     //最大顶点数
106     static const int MAX_VERTEX_NUM = 20;
107     Vertex m_vertices[MAX_VERTEX_NUM];    //顶点列表
108     int m_vertexNum;    //当前顶点数量
109     int m_arcNum;        //当前弧数量
110     GraphType m_type;    //图类型:有向无权图、有向带权图、无向无权图、无向无权图
111
112     //结点入度数组
113     int m_inDegreeArray[MAX_VERTEX_NUM];
114 private:
115     //初始化顶点列表
116     void InitVertices()
117     {
118         cout << "请输入每个顶点的关键字" << endl;
119         VertexType data;
120         for (int i = 0; i < m_vertexNum; ++i)
121         {
122             cin >> data;
123             m_vertices[i].data = data;
124         }
125     }
126     //插入一个表结点
127     void Insert(int headVertex, int tailVertex, InfoType info)
128     {
129         //构造一个邻接表结点,即创建一条弧
130         ArcNode* newNode = new ArcNode;
131         newNode->info = info;
132         newNode->next = nullptr;
133         newNode->vertexIndex = tailVertex;
134
135         //找到邻接表的最后一个节点
136         ArcNode* lastNode = m_vertices[headVertex].firstArc;
137         if (lastNode == nullptr)
138             m_vertices[headVertex].firstArc = newNode;
139         else
140         {
141             while (lastNode->next)
142             {
143                 lastNode = lastNode->next;
144             }
145             lastNode->next = newNode;
146         }
147         ++m_arcNum;
148     }
149
150     //创建有向无权图
151     void CreateDirUnweightGraph()
152     {
153         InitVertices();
154         cout << "请分别输入每条边的起始结点值:" << endl;
155         int head, tail;
156         while (cin >> head >> tail)
157         {
158             Insert(head, tail, 0);
159         }
160     }
161
162     void CountInDegree()
163     {
164         for (int i = 0; i < m_vertexNum; ++i)
165         {
166             m_inDegreeArray[i] = 0;
167             for (int j = 0; j < m_vertexNum; ++j)
168             {
169                 ArcNode* node = m_vertices[j].firstArc;
170                 while (node)
171                 {
172                     if (node->vertexIndex == i)
173                     {
174                         ++m_inDegreeArray[i];
175                     }
176                     node = node->next;
177                 }
178             }
179         }
180     }
181 };
182
183 int main()
184 {
185     Graph<char, int> g(6, DIR_UNWEIGHT_GRAPH);
186     g.Create();
187     g.Display();
188     g.TopologicalSort();
189 }

  测试用的有向图:

  输出结果:

时间: 2024-08-04 12:38:16

基于邻接表的拓扑排序实现的相关文章

数据结构实验之图论二:基于邻接表的广度优先搜索遍历

数据结构实验之图论二:基于邻接表的广度优先搜索遍历 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 给定一个无向连通图,顶点编号从0到n-1,用广度优先搜索(BFS)遍历,输出从某个顶点出发的遍历序列.(同一个结点的同层邻接点,节点编号小的优先遍历) 输入 输入第一行为整数n(0< n <100),表示数据的组数. 对于每组数据,第一行是三个整数k,m,t(0<k<100,0<m<(k-1)*k/2,

SDUT 2142 【TEST】数据结构实验之图论二:基于邻接表的广度优先搜索遍历

数据结构实验之图论二:基于邻接表的广度优先搜索遍历 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Discuss Problem Description 给定一个无向连通图,顶点编号从0到n-1,用广度优先搜索(BFS)遍历,输出从某个顶点出发的遍历序列.(同一个结点的同层邻接点,节点编号小的优先遍历) Input 输入第一行为整数n(0< n <100),表示数据的组数.对于每组数据,第一行是三个整数k,m,t(0<

基于邻接表的图建立(有向图+无向图)

图的表示(建立)有两种方法: ①邻接矩阵:A(i,j)=1表示i,j存在一条边,空间复杂度O(n^2),稠密图 ②邻接表:只记录存在的边,Vector+List的数据结构,稀疏图 邻接矩阵的图建立这里不做赘述,接下来我们看一下邻接表的图建立: <1>有向图 注意理解头插入节点的过程 int n,m;//n表示城镇个数,m表示道路条数</span> struct LinkNode//列表节点 { int vex; //邻接的结点在数组中的编号 LinkNode* next; }; s

拓扑排序(基于邻接表实现)

#include <iostream> #include <stack> using namespace std; #define MAX 100 typedef char VertexType; typedef struct ArcNode { int adjvex; //邻接点域,存储该弧指向顶点的下标 (终点) struct ArcNode *next; //指向下一条弧的指针 int weight; //权重 }ArcNode; //边结构 typedef struct V

JAVA邻接表实现拓扑排序

由于一直不适用邻接表 ,现在先贴一段使用邻接矩阵实现图的拓扑排序以及判断有无回路的问题.自己做的图.将就看吧. package TopSort; import java.util.LinkedList; import java.util.Scanner; /*拓扑序列:对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性 * 序列,使得图中任意一对顶点u和v,若<u,v> ∈E(G),则u在线性序列中出现在v之前. * */ p

基于邻接表存储的图的深度优先遍历和广度优先遍历

一.深度优先遍历是连通图的一种遍历策略.其基本思想如下: 设x是当前被访问顶点,在对x做过访问标记后,选择一条从x出发的未检测过的边(x,y).若发现顶点y已访问过,则重新选择另一条从x出发的未检测过的边,否则沿边(x,y)到达未曾访问过的y,对y访问并将其标记为已访问过:然后从y开始搜索,直到搜索完从y出发的所有路径,即访问完所有从y出发可达的顶点之后,才回溯到顶点x,并且再选择一条从x出发的未检测过的边.上述过程直至从x出发的所有边都已检测过为止. 例如下图中: 1.从0开始,首先找到0的关

数据结构学习笔记(十)-图的最小生成树与拓扑排序

一.最小生成树 首先应该理解最小生成树的定义: 包含图的所有顶点,V-1条边 没有回路 边的权重和最小 那么实际问题中用到最小生成树是什么时候呢?很多人都觉得学习算法没用,在实际生活工作中根本就用不上,其实并不是用不上,只是你根本没有想到要去用而已!使用了算法后你就会发现事情原来可以这么简单高效! 实际中如需要使用最少的电线给一栋房子安装电路.就可以用最小生成树解决. 1. Prim算法 该算法利用了贪心的思想,大体上与dijkstra算法类似,都需要对每一个顶点保存一个距离值dv和pv,以及一

算法系列(十三)图论基本概念和拓扑排序

图的定义 一个图G=(V,E),由定点的集合V,和边的集合E组成.每一条边都是一副点对(v,w),边也称作弧,边上可以有权值.如果点对是有序的,那么图就是有向的. 图中的一条路径是一个顶点序列w1,w2,w3......wN,如果图中包含一条从顶点到自身的边,那么这个路径就是环. 有向无环图也成为DAG 如果在一个无向图中每个顶点到其它顶点都存在路径,则称这个无向图是连通的.具有这样性质的有向图被称为是强连通的.如果一个有向图不是强连通的,但是去掉方向后的基础图是连通的,那么该有向图称为是弱连通

拓扑排序再续

[拓扑排序问题] 解决方法: 1. 计算每一个点的入度值deg[i],这一步需要扫描所有点和边,复杂度O(N+M). 2. 把入度为0的点加入队列Q中,当然有可能存在多个入度为0的点,同时它们之间也不会存在连接关系,所以按照任意顺序加入Q都是可以的. 3. 从Q中取出一个点p.对于每一个未删除且与p相连的点q,deg[q] = deg[q] - 1:如果deg[q]==0,把q加入Q. 代码:复杂度:O(V+E) <span style="font-size:14px;">