有向图(5)--一般化的有向图&&拓扑排序

前面几篇的博客都是用int型做为顶点去研究算法的

这样做的原因有:

1.一开始用太复杂的类型可能会导致学习困难

2.不管是什么类型都可以转换成用int型来表示,只需要一个符号表st和一个数组来做反索引即可

接下来就是一般化的有向图的代码

有关头文件在之前的几篇博客中都有

-SimbolDigraph.h

#ifndef __SYMBOL_DIGRAPH_H__
#define __SYMBOL_DIGRAPH_H__

#include "Digraph.h"
#include <map>
#include <string>
#include <vector>
#include <fstream>

void split(std::string line, char sp, std::list<std::string>& slst);

class SymbolDigraph {
private:
	std::map<std::string, int> st;		// 符号名	->	索引
	std::vector<std::string> keys;		// 索引	  ->  符号名
	Digraph* p_G;

public:
	SymbolDigraph(std::string fileName, char sp);	// @param fileName:文件名, sp:分隔符
	~SymbolDigraph() { delete p_G; }

	std::string name(int v)const { return keys[v]; }
	bool contain(std::string s)const { return (st.count(s) ? true : false); }
	int index(std::string s)const { return (contain(s) ? st.find(s)->second : -1); }
	Digraph getG()const { return *p_G; }

};

// constructor
SymbolDigraph::SymbolDigraph(std::string fileName, char sp) {
	// 读文件
	std::ifstream infile(fileName);
	std::string line;
	int count = 0;
	// 构造索引
	for (;;) {
		std::getline(infile, line);
		// 放在这里是因为文件最后一行是空的
		if (infile.eof()) break;	
		std::list<std::string> slst;
		split(line, sp, slst);
		for (std::string s : slst) {
			if (!st.count(s)) {
				st[s] = count++;
			}
		}
	}
	infile.close();
	// 构造反向索引
	keys.resize(count);
	std::map<std::string, int>::const_iterator iter;
	for (iter = st.begin(); iter != st.end(); ++iter)
		keys[iter->second] = iter->first;
	// 再次读文件构造图
	infile.open(fileName);
	p_G = new Digraph(count);
	for (;;) {
		std::getline(infile, line);
		// 放在这里是因为文件最后一行是空的
		if (infile.eof()) break;		
		std::list<std::string> slst;
		split(line, sp, slst);
		// n-判断s是不是第一个字符串
		int n = 0;
		std::string tmpStr;	// 存储第一个字符串
		for (std::string s : slst) {
			if (n == 0) { 
				n = 1;
				tmpStr = s;
			}
			else
				p_G->addEdge(st[tmpStr], st[s]);
		}
	}
	infile.close();
}

// 字符串分割:split
void split(std::string line, char sp, std::list<std::string>& slst) {
	std::string::iterator iter1, iter2;
	iter1 = line.begin();
	for (;;) {
		iter2 = find(iter1, line.end(), sp);
		slst.push_back(std::string(iter1, iter2));
		if (iter2 == line.end()) break;
		iter1 = ++iter2;
	}
}

#endif

这里的构造函数是从文件fileName中读取字符串,以sp为分隔符

每行的第一个字符串为顶点,后面的字符串是第一个字符串指向的顶点。

下面是我的文件(jobs.txt)中的内容

Algorithms/Theoretical CS/Databases/Scientific Computing
Introduction to CS/Advanced Programming/Algorithms
Advanced Programming/Scientific Computing
Scientific Computing/Computational Biology
Theoretical CS/Computational Biology/Artificial Intelligence
Linear Algebra/Theoretical CS
Calculus/Linear Algebra
Artificial Intelligence/Neural Networks/Robotics/Machine Learning
Machine Learning/Neural Networks


拓扑排序:给定一幅有向图,将所有的顶点排序,使得所有的有向边均从排在前面的元素指向排在后面的元素(或者说明无法做到这一点)。

上面的文件中的内容是一个正在安排的课程,每行的第一个学科是这一行后面其他学科的先导课程。

下面上拓扑排序的代码:

-Topological.h

#ifndef __TOPOLOGICAL_H__
#define __TOPOLOGICAL_H__

#include "Digraph.h"
#include "DirectedCycle.h"
#include "DepthFirstOrder.h"
#include <iostream>

class Topological {
private:
	std::stack<int> order;

public:
	Topological(const Digraph& G);

	std::stack<int> getOrder()const { return order; }
	bool isDAG()const { return !order.empty(); }

};

Topological::Topological(const Digraph& G) {
	DirectedCycle cycleFinder(G);
	if (!cycleFinder.hasCycle()) {
		DepthFirstOrder dpo(G);
		order = dpo.getReversePost();
	}
	else {
		std::stack<int> stk = cycleFinder.getCycle();
		while (!stk.empty()) {
			std::cout << stk.top() << " ";
			stk.pop();
		}
	}
}

#endif


-main.cpp 测试代码

#include "Topological.h"
#include "SymbolDigraph.h"
#include <iostream>
using namespace std;

int main()
{
	string fileName = "jobs.txt";
	char sp = '/';

	SymbolDigraph sg(fileName, sp);

	Topological top(sg.getG());

	stack<int> stk = top.getOrder();

	while (!stk.empty()) {
		cout << sg.name(stk.top()) << endl;
		stk.pop();
	}

	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值