Directed Acyclic Graph - AOV Network and Topological Sorting

Directed Acyclic Graph - AOV Network and Topological Sorting

Directed Acyclic Graph

An acyclic directed graph is called a directed acyclic graph , or DAG for short.

Its application is roughly as follows:

  • It has extensive and important applications in engineering planning and management
  • Effective tool for describing the progress of a project or system
  • For the entire project and system, people are concerned about two issues: one is whether the project can be carried out smoothly; the other is the shortest time necessary to complete the entire project. Corresponding to the directed graph is to perform topological sorting and find the critical path.

This article discusses the AOV network and its topological sorting separately

AOV network and topological sorting

concept

AOV network: A directed acyclic graph that uses vertices to represent activities and arcs to represent the priority relationship between activities is called Activity On Vertex network (Activity On Vertex network), referred to as AOV network.

Topological sorting: the process of arranging the vertices in the AOV network into a linear sequence (topological sequence) according to their mutual priority relationship. If all vertices in the network are in its topologically ordered sequence, then the topological sequence is a feasible solution for the successful completion of a project; otherwise, the project cannot be successfully completed.

Topological sort method:

  • Select a vertex output with in-degree 0 from the graph
  • deletes the vertex and all arcs originating from the vertex from the graph
  • Repeat the above two steps until all vertices are output, and the topological sorting is successfully completed. Otherwise, if there are vertices with non-zero in-degree remaining, it means that there is a cycle in the graph, and topological sorting cannot be performed

topological sort code

AOV net class definition

class aov {
    
    
public:
	aov() {
    
    }
private:
	class node {
    
    
	public:
		set<int> prev;	//前驱结点
		set<int> next;	//后继结点

		//备份
		set<int> back_prev;
		set<int> back_next;

	};

	unordered_map<int, node*> adjList;	//邻接表

public:
	void Insert(int index, initializer_list<int> lst);
	bool DeleteArc(int a, int b);
	void Sort();

private:
	void _Sort(unordered_map<int, node*> adjList);
};

insert operation

//插入
void aov::Insert(int index, initializer_list<int> lst) {
    
    
	//若当前结点不存在则创建
	node* n = this->adjList[index] ? this->adjList[index] : new node;

	for (auto it = lst.begin(); it != lst.end(); it++)
	{
    
    
		//将该节点后继插入到后继索引集合中去
		n->next.insert(*it);
		n->back_next.insert(*it);
		node* p = nullptr;
		
		//若后继结点不存在,则创建
		if (this->adjList[*it] == nullptr)
		{
    
    
			p = new node;
			this->adjList[*it] = p;
		}
		else {
    
    
			p = this->adjList[*it];
		}
		
		//向相连结点记入前驱
		p->prev.insert(index);
		p->back_prev.insert(index);
	}

	this->adjList[index] = n;	//保存至邻接表
}

delete relationship

//删除a指向b之间的关系(注意,这里有方向规定)
bool aov::DeleteArc(int a, int b)
{
    
    
	//如果不存在a结点或b结点则返回false
	if (this->adjList[a] == nullptr || this->adjList[b] == nullptr)
		return false;

	node* p_a = this->adjList[a];
	node* p_b = this->adjList[b];

	auto p_a_find = p_a->next.find(b);
	auto p_b_find = p_b->prev.find(a);

	if (p_a_find != p_a->next.end())
		p_a->next.erase(p_a_find);

	if (p_b_find != p_b->prev.end())
		p_b->prev.erase(p_b_find);

	p_a_find = p_a->back_next.find(b);
	p_b_find = p_b->back_prev.find(a);

	if (p_a_find != p_a->back_next.end())
		p_a->back_next.erase(p_a_find);

	if (p_b_find != p_b->back_prev.end())
		p_b->back_prev.erase(p_b_find);


	return true;
}

topological sort

//拓扑排序
void aov::_Sort(unordered_map<int, node*> adjList)
{
    
    
	stack<int> st;

	if (adjList.size() == 0)
	{
    
    
		cout << endl;
		return;
	}

	for (auto it = adjList.begin(); it != adjList.end(); it++)
	{
    
    
		if (it->second->prev.size() == 0)
			st.push(it->first);
	}
	
	while (!st.empty())
	{
    
    
		int t = st.top();
		cout << t << " ";
		st.pop();

		//对t指向的每一个结点删除弧,及这些结点入度都减1
		for (auto it = adjList[t]->next.begin(); it != adjList[t]->next.end(); it++)
		{
    
    
			if (adjList[*it])
			{
    
    
				auto index = adjList[*it]->prev.find(t);
				if (index != adjList[*it]->prev.end())
					adjList[*it]->prev.erase(index);
			}
		}

		adjList.erase(t);
	}

	_Sort(adjList);

}

void aov::Sort()
{
    
    
	_Sort(this->adjList);
	//排序会破坏结点之间的关系,利用备份重新回复原有关系
	for (auto it = this->adjList.begin(); it != this->adjList.end(); it++)
	{
    
    
		it->second->next = it->second->back_next;
		it->second->prev = it->second->back_prev;
	}

}

test

int main()
{
    
    
	aov* v = new aov;
	
	v->Insert(1, {
    
     2,3,4 });
	v->Insert(3, {
    
     2,5 });
	v->Insert(4, {
    
     5 });
	v->Insert(6, {
    
     4,5 });

	v->Sort();
	v->Sort();
	return 0;
}

Code shortcomings

For topological sorting, I didn't think about this way of writing at the beginning. Using pointers for topological sorting will destroy the connection between nodes, so I use a backup set to restore, but this operation will take up some more resources.

おすすめ

転載: blog.csdn.net/qq_42759112/article/details/127752436