目录
一、实验目的和要求
设计算法并实现有向无环图的所有拓扑序列。
二、实验环境
软件环境:visual stdio 2017
硬件环境:①CPU:Intel(R)Core(TM)i7-8565U CPU @1.80Ghz
②内存:8.0GB
三、实验内容
设计算法并实现有向无环图的所有拓扑序列。
四、实验过程
4.1 任务定义和问题分析
问题拆分:
1°以邻接链表为存储结构,对有向无环图进行类的封装
2°输入点、边信息,对输入信息进行检测,判断是否为无环图
3°设计递归回溯的拓扑排序算法,输出所有拓扑序列
4.2 数据结构的选择和概要设计
采用的数据结构:自行设计的邻接链表与DAG有向无环图类,STL中的stack与vector。
4.3 详细设计
主要函数设计:
1°DEL函数:对动态分配的内存进行delete,delete的内容有邻接链表,入度动态数组。
2°无环图判断函数:基于栈利用非递归的方法尝试获取一个拓扑序列,若序列长度与结点数相同,则返回true。
3°构造函数:输入信息进行初始化工作,并检查是否为无环图,若非无环图,则先调用DEL函数,再通过goto语句重新输入。
4°析构函数:调用保护成员DEL函数,进行所有动态分配内存的delete。
5°拓扑排序函数:采用递归回溯的方法,输出所有拓扑序列
算法设计:采用string型vector储存每个结点的data值,对结点进行for循环遍历,若探寻到入度为0的点,则对其所有邻结点进行入度-1的操作,并将该点push进vector。递归调用拓扑排序函数。接下来的代码部分便是回溯之后执行的操作:对所有邻结点进行入度+1的操作,并对vector进行pop操作。即对递归前的操作进行取消,这样是为了使本次获取一个拓扑序列的操作不影响到其他拓扑序列的获取。递归出口为,vector的大小与结点数目相同,此时输出vector中所有值,并return。
五、测试及结果分析
5.1 实验数据
5.2 结果及分析
输出结果均正确
六、实验收获
通过本次实验,我对递归回溯算法有了进一步的认识与理解,也学会了拓扑排序的应用——判断图是否为无环图。
此外,编程水平也得到了一定的提升。
七、源代码
#include<iostream>
#include<string>
#include<vector>
#include<stack>
using namespace std;
struct AdjNode
{
string data;
int index;
AdjNode* next;
};
struct AdjList
{
AdjNode node;
bool isvisted;
};
class DAG
{
public:
DAG(); //初始化
~DAG();
void Topo_Sort(); //输出所有拓扑序列
protected:
void Topo_Sort(vector<string>& order); //递归回溯
bool isAcyclic(); //拓扑排序判断是否为无环图
void DEL(); //delete动态分配内存
private:
struct AdjList* list; //邻接表
int V_num; //顶点数
int *In_degree; //各点入度
};
void DAG::DEL()
{
for (int i = 1; i <= V_num; i++)
{
while (list[i].node.next != NULL)
{
AdjNode* p = new AdjNode;
p = list[i].node.next;
list[i].node.next = p->next;
delete p;
}
}
delete[]list;
delete[]In_degree;
}
bool DAG::isAcyclic()
{
stack<int> s;
int count = 0;
int *In = new int[V_num + 1];
for (int i = 1; i <= V_num; i++)
{
In[i] = In_degree[i];
}
for (int i = 1; i <= V_num; i++)
if (In[i] == 0) s.push(i);
while (!s.empty())
{
int temp=s.top();
s.pop();
count++;
AdjNode* p = list[temp].node.next;
while (p != NULL)
{
In[p->index]--;
if (In[p->index] == 0) s.push(p->index);
p = p->next;
}
}
delete[]In;
return count == V_num;
}
DAG::DAG()
{
L1:
cout << "请输入所有顶点数:";
cin >> V_num;
list = new AdjList[V_num + 1];
In_degree = new int[V_num + 1];
memset(In_degree, 0, (V_num + 1) * sizeof(int));
cout << "请依次输入每个顶点的名称:" << endl;
for (int i = 1; i <= V_num; i++)
{
cin >> list[i].node.data;
list[i].node.index = i;
list[i].node.next = NULL;
}
for (int i = 1; i <= V_num; i++)
{
int size;
cout << "请输入第" << i << "个顶点的指向顶点的数量:";
cin >> size;
for (int j = 1; j <= size; j++)
{
int index;
cout << "请输入第" << j << "个邻接点的编号:";
cin >> index;
In_degree[index]++;
AdjNode* p = new AdjNode;
p->index = index;
p->next = list[i].node.next;
list[i].node.next = p;
}
}
if (isAcyclic()) cout << "经拓扑排序检测,输入信息符合无环图" << endl;
else
{
DEL();
cout << "经拓扑排序检测,输入信息不符合无环图,请重新输入" << endl;
goto L1;
}
}
DAG::~DAG()
{
DEL();
}
void DAG::Topo_Sort()
{
vector<string>order;
for (int i = 1; i <= V_num; i++)
{
list[i].isvisted = false;
}
Topo_Sort(order);
}
void DAG::Topo_Sort(vector<string>& order )
{
if (order.size() == V_num)
{
for (int i = 0; i < order.size(); i++)
cout << order[i] << " ";
cout << endl;
}
for (int i = 1; i <= V_num; i++)
{
if (!In_degree[i] && !list[i].isvisted)
{
list[i].isvisted = true;
order.push_back(list[i].node.data);
AdjNode* p = list[i].node.next;
while (p != NULL)
{
In_degree[p->index]--;
p = p->next;
}
Topo_Sort(order);
list[i].isvisted = false;
order.pop_back();
AdjNode*q = list[i].node.next;
while (q != NULL)
{
In_degree[q->index]++;
q = q->next;
}
}
}
}
int main()
{
DAG graph;
cout << "该图所有拓扑序列为:" << endl;
graph.Topo_Sort();
return 0;
}