功能描述:建立图的存储结构,能够输入图的顶点和边的信息,并存储到相应存储结构中,再编写函数实现图的拓扑排序。
设计要求:选择邻接表作为有向图的存储结构模拟整个过程,并输出拓扑排序的顶点序列,利用下图中的数据调试程序。
环境: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文件中