c++语言数据结构有向图实现拓扑排序(按顶点序数小的优先)

功能描述:建立图的存储结构,能够输入图的顶点和边的信息,并存储到相应存储结构中,再编写函数实现图的拓扑排序。

设计要求:选择邻接表作为有向图的存储结构模拟整个过程,并输出拓扑排序的顶点序列,利用下图中的数据调试程序。

 环境:dev-c++

#include <iostream>
#include <fstream>
#include <iomanip> 
#include <stack>
#include <queue>

using namespace std;

#define MAX_VERTEX_NUM  20   //最大顶点个数 

typedef struct NeighborList{  //  这时邻接表的每一个弧的结构 
	int index;  //  是哪个顶点 
	NeighborList * PNL;  //  指向该弧下一个弧的指针
	string *info;  //  指向该弧的存储信息  先定为string类型 
}* NeighborListPointer;
//typedef NeighborList * NeighborListPointer;

typedef struct HeadList{  //  头结点结构  后面拖着长长的弧  一个头结点代表一个顶点 
	int vertex;  //  顶点域  放顶点序号 
	string name;  //  头结点的名称 
	NeighborList * PNL;  //  指向后方第一个弧的指针
}AdjList[MAX_VERTEX_NUM];

typedef struct GraphStatus{  //  图当前的状态

	AdjList vertices;  //  联系这个图和各个顶点
	int	vexnum,arcnum;  //  图的顶点数,边数 

}GraphStatus;

bool CreateGraph(GraphStatus& G,int n,int m,int a[]);
bool TopRange(GraphStatus& G,int h);

static vector<int> indegree(50);  //  记录每个顶点入度的数组,下表对应顶点
ofstream outfile;

bool CreateGraph(GraphStatus& G,int n,int m,int a[]){  //  n是顶点数 m是边数 a是存放各个顶点位置的 

	G.vexnum = n;  //  顶点数 
	G.arcnum = m;  //  边数 

	//cout<<G.vexnum<<G.arcnum;
	
	for(int i=1;i<=G.vexnum;i++){  //  创建默认顶点信息
		
		//cin >> G.vertices[m].vertex;  //  输入每个顶点的序号
		G.vertices[i].vertex = a[i];  //  顶点序号默认从1开始排列
		G.vertices[i].PNL = 0;  //  顶点默认弧指针为空 
	}
	outfile<<"输入的有向图的边"<<endl;
	for(int j=0;j<G.arcnum;j++){  //  循环输入所有边的信息创建邻接表 
		
		int x,y;
		cin >> x >> y;  //  输入两个数  x指y  插在头结点的的后面
		outfile<<setw(2)<< x << "  "<<setw(2)<< y << "    ";
		indegree[y]++;  //  y的入度加一 
		NeighborListPointer s = new NeighborList;  //  每次都新申请一个弧结点 
		s -> index = y;  //  这个新弧的index设为y 
		s -> PNL = G.vertices[x].PNL;  //  新弧后指针改为头结点后指针
		G.vertices[x].PNL = s;  //  头结点后指针指向新弧  完成新弧插入到头结点的后面一个位置 
		
	}
	outfile<<endl;

	return true;
}



bool TopRange(GraphStatus& G,int h){
	//extern vector<int> indegree;
	cout<<"过程可视 左边的是入列顶点  右边的是该顶点入列后入度数组的变化  入列后的顶点设为10"<<endl;
	
	//stack <int> S;
	queue <int> q;
	for(int j=1;j<h+1;j++){ 
		for(int i=1;i<h+1;i++){  //  检查整个入度数组 
			
			if(indegree[i]==0){  //  如果找到入度变为0的顶点 
				cout<<setw(2)<< i << "  ";  //  这个顶点的入度为0 
				outfile<<setw(2)<< i << "    ";
				//S.push(i);
				q.push(i);  //  这个顶点入队 
				if(G.vertices[i].PNL!=0){  //  只要这个顶点后面不为空 
				NeighborListPointer p;  //  搞一个指向弧的指针类型 
				p = G.vertices[i].PNL;  //  让这个指针指向顶点的下一个弧 
				//cout<<G.vertices[i].PNL<<"        ";
				//cout << p->index<<"  ";
				for(;p->PNL!=NULL;p=p->PNL){  //  尾之前 
					indegree[p -> index]--;  //  更新入度数组 
				}
				//cout<< p -> index<<"  ";
				//cout<<p->PNL<<"  ";
				if(p->PNL==0){  //  尾部 
					indegree[p -> index]--;  //  更新入度数组 
				} 
				}  //  找这个点都指了谁,把他们的入度减一 
				indegree[i] = 10;  //  后面这个顶点别捣乱 

				for(int m=1;m<h+1;m++){
					cout<<setw(3)<<indegree[m]<<" ";
					outfile<<setw(3)<<indegree[m]<<" ";
				}
				cout<<endl;
				outfile<<endl;
				break;
			}
			
		}
	}
	cout<<"拓扑排序  按顶点序数小的优先" <<endl;
	outfile << "拓扑排序结果" <<endl;
	for(int n=1;n<h+1;n++){
		cout<<q.front()<<"  ";
		outfile <<q.front()<<"  ";
		q.pop();
	}
	outfile <<endl;
	return true;
} 



int main(int argc, char** argv) {
	outfile.open("out.txt",ios::app);
	GraphStatus G;
	//int a[]={1,2,3,4,5,6,7,8,9,10,11,12};  //  定点序号数组
	cout<<"输入顶点个数和边个数 示例:12 16"<<endl; 
	int i,j,k,a[500];
	cin>> i >> j;
	outfile<<"输入的有向图数据为"<<endl;
	outfile<<"顶点个数:"<<i<<"  边个数:"<<j<<endl;
	k=i;
	for(;k>0;k--){  //  循环k次 
		a[k]=k;
	}
	cout<<"输入有向图 示例:1 12 1 4 1 3 1 2 2 3 3 8 3 7 3 5 4 5 5 7 6 8 9 12 9 11 9 10 10 12 11 6"<<endl;
	CreateGraph(G,i,j,a);  //  创建邻接表 
	outfile<<"排序过程数组变化,左边的是入列顶点,右边的是该顶点入列后入度数组的变化,入列后的顶点设为10。"<<endl;
	TopRange(G,i);
	outfile<<endl; 
	outfile.close();
	return 0;
}

运行示例

 再试一个5顶点5条边的

 运行结果

储存在out文件中

 

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是按字典序数输出的欧拉路径模板的 C++ 实现: ```c++ #include <iostream> #include <vector> #include <set> #include <algorithm> using namespace std; vector<set<int>> graph; void dfs(int u, vector<int> &path) { while (!graph[u].empty()) { int v = *graph[u].begin(); graph[u].erase(v); graph[v].erase(u); dfs(v, path); } path.push_back(u); } vector<int> euler_path(int n, vector<pair<int, int>>& edges) { // 构建邻接表 graph.assign(n, set<int>()); for (auto& edge : edges) { graph[edge.first].insert(edge.second); graph[edge.second].insert(edge.first); } // 找到起点 int start = 0; while (graph[start].empty() && start < n) { start++; } // 检查是否存在欧拉路径 int odd_vertices = 0; for (int u = 0; u < n; u++) { if (graph[u].size() % 2 == 1) { odd_vertices++; } } if (odd_vertices != 0 && odd_vertices != 2) { cout << "No Euler path found." << endl; return {}; } // 求解欧拉路径 vector<int> path; dfs(start, path); reverse(path.begin(), path.end()); return path; } int main() { int n = 5; vector<pair<int, int>> edges = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 0}, {0, 2}, {2, 4}}; vector<int> path = euler_path(n, edges); for (int u : path) { cout << u << " -> "; } cout << endl; return 0; } ``` 在这个模板中,我们首先构建了一个邻接表来表示图的结构。然后我们检查是否存在欧拉路径。如果存在欧拉路径,我们从起点开始,按照字典序的顺序遍历图中的每一个节点,并把它们依次添加到路径中。最后,我们按照反向顺序输出路径即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值