/*** C++: 无回路有向图(Directed Acyclic Graph)的拓扑排序*      该DAG图是通过邻接表实现的。  ** @author judyge* @date 2014/04/22*/#include <iomanip>
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;#define MAX 100
// 邻接表
class ListDG
{private: // 内部类// 邻接表中表对应的链表的顶点class ENode{int ivex;           // 该边所指向的顶点的位置ENode *nextEdge;    // 指向下一条弧的指针friend class ListDG;};// 邻接表中表的顶点class VNode{char data;          // 顶点信息ENode *firstEdge;   // 指向第一条依附该顶点的弧friend class ListDG;};private: // 私有成员int mVexNum;             // 图的顶点的数目int mEdgNum;             // 图的边的数目VNode *mVexs;            // 图的顶点数组public:// 创建邻接表对应的图(自己输入)ListDG();// 创建邻接表对应的图(用已提供的数据)ListDG(char vexs[], int vlen, char edges[][2], int elen);~ListDG();// 深度优先搜索遍历图void DFS();// 广度优先搜索(类似于树的层次遍历)void BFS();// 打印邻接表图void print();// 拓扑排序int topologicalSort();private:// 读取一个输入字符char readChar();// 返回ch的位置int getPosition(char ch);// 深度优先搜索遍历图的递归实现void DFS(int i, int *visited);// 将node节点链接到list的最后void linkLast(ENode *list, ENode *node);
};/** 创建邻接表对应的图(自己输入)*/
ListDG::ListDG()
{char c1, c2;int v, e;int i, p1, p2;ENode *node1, *node2;// 输入"顶点数"和"边数"cout << "input vertex number: ";cin >> mVexNum;cout << "input edge number: ";cin >> mEdgNum;if ( mVexNum < 1 || mEdgNum < 1 || (mEdgNum > (mVexNum * (mVexNum-1)))){cout << "input error: invalid parameters!" << endl;return ;}// 初始化"邻接表"的顶点mVexs = new VNode[mVexNum];for(i=0; i<mVexNum; i++){cout << "vertex(" << i << "): ";mVexs[i].data = readChar();mVexs[i].firstEdge = NULL;}// 初始化"邻接表"的边for(i=0; i<mEdgNum; i++){// 读取边的起始顶点和结束顶点cout << "edge(" << i << "): ";c1 = readChar();c2 = readChar();p1 = getPosition(c1);p2 = getPosition(c2);// 初始化node1node1 = new ENode();node1->ivex = p2;// 将node1链接到"p1所在链表的末尾"if(mVexs[p1].firstEdge == NULL)mVexs[p1].firstEdge = node1;elselinkLast(mVexs[p1].firstEdge, node1);}
}/** 创建邻接表对应的图(用已提供的数据)*/
ListDG::ListDG(char vexs[], int vlen, char edges[][2], int elen)
{char c1, c2;int i, p1, p2;ENode *node1, *node2;// 初始化"顶点数"和"边数"mVexNum = vlen;mEdgNum = elen;// 初始化"邻接表"的顶点mVexs = new VNode[mVexNum];for(i=0; i<mVexNum; i++){mVexs[i].data = vexs[i];mVexs[i].firstEdge = NULL;}// 初始化"邻接表"的边for(i=0; i<mEdgNum; i++){// 读取边的起始顶点和结束顶点c1 = edges[i][0];c2 = edges[i][1];p1 = getPosition(c1);p2 = getPosition(c2);// 初始化node1node1 = new ENode();node1->ivex = p2;// 将node1链接到"p1所在链表的末尾"if(mVexs[p1].firstEdge == NULL)mVexs[p1].firstEdge = node1;elselinkLast(mVexs[p1].firstEdge, node1);}
}/* * 析构函数*/
ListDG::~ListDG()
{ENode *node;for(int i=0; i<mEdgNum; i++){node = mVexs[i].firstEdge;while (node != NULL){delete node;node = node->nextEdge;}}delete[] mVexs;
}/** 将node节点链接到list的最后*/
void ListDG::linkLast(ENode *list, ENode *node)
{ENode *p = list;while(p->nextEdge)p = p->nextEdge;p->nextEdge = node;
}/** 返回ch的位置*/
int ListDG::getPosition(char ch)
{int i;for(i=0; i<mVexNum; i++)if(mVexs[i].data==ch)return i;return -1;
}/** 读取一个输入字符*/
char ListDG::readChar()
{char ch;do {cin >> ch;} while(!((ch>='a'&&ch<='z') || (ch>='A'&&ch<='Z')));return ch;
}/** 深度优先搜索遍历图的递归实现*/
void ListDG::DFS(int i, int *visited)
{ENode *node;visited[i] = 1;cout << mVexs[i].data << " ";node = mVexs[i].firstEdge;while (node != NULL){if (!visited[node->ivex])DFS(node->ivex, visited);node = node->nextEdge;}
}/** 深度优先搜索遍历图*/
void ListDG::DFS()
{int i;int *visited;       // 顶点访问标记visited = new int[mVexNum];// 初始化所有顶点都没有被访问for (i = 0; i < mVexNum; i++)visited[i] = 0;cout << "== DFS: ";for (i = 0; i < mVexNum; i++){if (!visited[i])DFS(i, visited);}cout << endl;delete[] visited;
}/** 广度优先搜索(类似于树的层次遍历)*/
void ListDG::BFS()
{int head = 0;int rear = 0;int *queue;     // 辅组队列int *visited;   // 顶点访问标记int i, j, k;ENode *node;queue = new int[mVexNum];visited = new int[mVexNum];for (i = 0; i < mVexNum; i++)visited[i] = 0;cout << "== BFS: ";for (i = 0; i < mVexNum; i++){if (!visited[i]){visited[i] = 1;cout << mVexs[i].data << " ";queue[rear++] = i;  // 入队列}while (head != rear) {j = queue[head++];  // 出队列node = mVexs[j].firstEdge;while (node != NULL){k = node->ivex;if (!visited[k]){visited[k] = 1;cout << mVexs[k].data << " ";queue[rear++] = k;}node = node->nextEdge;}}}cout << endl;delete[] visited;delete[] queue;
}/** 打印邻接表图*/
void ListDG::print()
{int i,j;ENode *node;cout << "== List Graph:" << endl;for (i = 0; i < mVexNum; i++){cout << i << "(" << mVexs[i].data << "): ";node = mVexs[i].firstEdge;while (node != NULL){cout << node->ivex << "(" << mVexs[node->ivex].data << ") ";node = node->nextEdge;}cout << endl;}
}/** 拓扑排序** 返回值:*     -1 -- 失败(由于内存不足等原因导致)*      0 -- 成功排序,并输入结果*      1 -- 失败(该有向图是有环的)*/
int ListDG::topologicalSort()
{int i,j;int index = 0;int head = 0;           // 辅助队列的头int rear = 0;           // 辅助队列的尾int *queue;             // 辅组队列int *ins;               // 入度数组char *tops;             // 拓扑排序结果数组,记录每个节点的排序后的序号。ENode *node;ins   = new int[mVexNum];queue = new int[mVexNum];tops  = new char[mVexNum];memset(ins, 0, mVexNum*sizeof(int));memset(queue, 0, mVexNum*sizeof(int));memset(tops, 0, mVexNum*sizeof(char));// 统计每个顶点的入度数for(i = 0; i < mVexNum; i++){node = mVexs[i].firstEdge;while (node != NULL){ins[node->ivex]++;node = node->nextEdge;}}// 将所有入度为0的顶点入队列for(i = 0; i < mVexNum; i ++)if(ins[i] == 0)queue[rear++] = i;          // 入队列while (head != rear)                // 队列非空{j = queue[head++];              // 出队列。j是顶点的序号tops[index++] = mVexs[j].data;  // 将该顶点添加到tops中,tops是排序结果node = mVexs[j].firstEdge;      // 获取以该顶点为起点的出边队列// 将与"node"关联的节点的入度减1;// 若减1之后,该节点的入度为0;则将该节点添加到队列中。while(node != NULL){// 将节点(序号为node->ivex)的入度减1。ins[node->ivex]--;// 若节点的入度为0,则将其"入队列"if( ins[node->ivex] == 0)queue[rear++] = node->ivex;  // 入队列node = node->nextEdge;}}if(index != mVexNum){cout << "Graph has a cycle" << endl;delete queue;delete ins;delete tops;return 1;}// 打印拓扑排序结果cout << "== TopSort: ";for(i = 0; i < mVexNum; i ++)cout << tops[i] << " ";cout << endl;delete queue;delete ins;delete tops;return 0;
}int main()
{char vexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};char edges[][2] = {{'A', 'G'}, {'B', 'A'}, {'B', 'D'}, {'C', 'F'}, {'C', 'G'}, {'D', 'E'}, {'D', 'F'}}; int vlen = sizeof(vexs)/sizeof(vexs[0]);int elen = sizeof(edges)/sizeof(edges[0]);ListDG* pG;// 自定义"图"(输入矩阵队列)//pG = new ListDG();// 采用已有的"图"pG = new ListDG(vexs, vlen, edges, elen);pG->print();   // 打印图//pG->DFS();     // 深度优先遍历//pG->BFS();     // 广度优先遍历pG->topologicalSort();     // 拓扑排序return 0;
}

ACM 模板--邻接表 有向图 拓扑排序相关推荐

  1. ACM 模板--邻接表 有向图 搜索算法

    邻接表图的广度优先搜索 深度递归与非递归搜索 /*** C++: 邻接表图** @author judyge* @date 2014/04/19*/#include <iomanip> # ...

  2. 邻接表存储 - 拓扑排序算法

    拓扑排序:用下面的例子介绍------> ---------------------------------------------------------------------------- ...

  3. 2192. 有向无环图中一个节点的所有祖先(邻接表 加 拓扑排序)

    如果直接使用邻接表不记录已经遍历过的数,暴力搜索超超时,所以需要拓扑排序来记录入度为0的点,入度为0时,他之前的父节点已经记录完毕,可以直接加入到他的子节点中. 最后还需要转换结果,从小到大,直接用s ...

  4. ACM模板--邻接表 无向图 Prim Kruskal Dijkstra

    /*** C++: Dijkstra算法获取最短路径(邻接表)** @author judyge* @date 2014/04/24*/#include <iomanip> #includ ...

  5. ACM 模板--邻接表 无向图 搜索算法

    图的 广度优先搜索 深度递归与非递归搜索 /*** C++: 邻接表表示的"无向图(List Undirected Graph)"** @author judyge* @date ...

  6. 教学计划编制问题(数据结构 有向图 拓扑排序)

    本文对以下教学计划编制问题的解决作出实现,主要使用c语言(带一点cpp),开发环境为codeblocks 17.12,希望对各位读者有所帮助.(源码和数据文件可在主页获取,数据文件需要和exe在同一目 ...

  7. C/C++二级指针概念及应用(有向图的邻接表(拓扑排序)、有向网图的邻接表、树的孩子表示)

    目录 一.概述 例1: 例2: 代码: 二.实例 1.有向图的邻接表(拓扑排序) 2.有向网图的邻接表 3.树的孩子表示 一.概述 二级指针:指向指针的指针.一般需要修改地址的时候会用到二级指针. 注 ...

  8. 图的拓扑排序(AOV网络)

    文章目录 拓扑排序 概念 实现 邻接表(队列) 邻接矩阵(栈) 总结 源代码 邻接表 邻接矩阵 拓扑排序 概念 拓扑排序是对有向无环图的顶点的一种排序. AOV网络 : 在有向图中, 用顶点表示活动或 ...

  9. 【算法】图(一)拓扑排序的实现 图的邻接表算法 判断是否图G中存在环

    文章目录 用list来表示图,判断是否存在环 邻接表实现拓扑排序 用DFS(邻接矩阵) 来实现拓扑排序. 判断无向图顶点是否全部连通 判断图G中从顶点u到v是否存在简单路径 输出图G中从顶点u到v的所 ...

最新文章

  1. String,StringBuffer,StringBuilder三者的异同
  2. Centos6.X升级glibc解决“libc.so.6 version GLIBC_2.14 not found”报错问题
  3. Torchvision目标检测模型训练过程记录
  4. Git Rebase教程: 用Git Rebase让时光倒流
  5. prefuse学习(一)用非数据库连接和xml的方式读入数据
  6. php 复选框全选和取消,基于JavaScript实现复选框的全选和取消全选
  7. zabbix v3.0安装部署【转】
  8. .NET设计模式(3): 抽象工厂模式
  9. bzoj1012: [JSOI2008]最大数maxnumber [单调队列]
  10. mysqldump实现数据备份及灾难恢复
  11. 安卓10未知来源_华为已将“基于安卓10”变成“兼容安卓10”,EMUI就是鸿蒙OS
  12. Android中的WebView之loadDataWithBaseURL()与loadData()
  13. 测试开发必备技能与成长路径
  14. 探索“云计算”的双重含义(节选)
  15. 小D课堂 - 零基础入门SpringBoot2.X到实战_第8节 数据库操作之整合Mybaties和事务讲解_35、事务介绍和常见的隔离级别,传播行为...
  16. 云酷科技UWB定位系统:智能巡检的新方式
  17. 手机投屏到电脑的5种方式,你学到了吗!
  18. 乌班图nginx访问php 变成下载
  19. kali安装WingIDE遇到软件依赖性问题的处理
  20. 50EX全球化战略布局加快,日韩版本将上线

热门文章

  1. 【Java 并发编程】线程锁机制 ( 线程安全 | 锁机制 | 类锁 | 对象锁 | 轻量级锁 | 重量级锁 )
  2. 【Android 事件分发】事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )
  3. 【数据挖掘】基于划分的聚类方法 ( K-Means 算法简介 | K-Means 算法步骤 | K-Means 图示 )
  4. 梳理一下我理解的aop
  5. Informatica ETL workflow 定时运行功能介绍 scheduler
  6. Python学习笔记之爬取网页保存到本地文件
  7. 解决yum错误Error: requested datatype primary not available
  8. PYTHON调用JENKINS的API来进行CI
  9. statspack系列8
  10. 这种有序神经元,像你熟知的循环神经网络吗?