zoukankan      html  css  js  c++  java
  • 拓扑排序

    1、什么是拓扑排序

    对于有向无环图G=(V,E),G的拓扑排序是G中全部节点的一种线性次序。该次序满足例如以下条件:对于图中的一

    有向边<u。v>,在拓扑排序中u节点位于v节点的前面(假设图G包括回路,则不可能排出一个线性次序)。能够将图的拓扑排序看做是将图的全部节点排在一条水平线上,有向图中的全部有向边都从左指向右。

    2、拓扑排序解决的实际问题

    我在这里介绍使用拓扑排序解决现实生活中的一个起床穿衣的问题。

    在起床的过程中,我们必须先穿某些衣服,

    后再去穿另外一些衣服。有些衣服则能够以随意顺序穿上,在下图中有向边<u,v>表明服装u必须在服装v之前穿上。

    我们该怎样解决穿衣问题呢?

    3、拓扑排序算法
    我们须要两个队列集合A、B,当中集合A用来存放入度为0的节点,集合B用来存放排好序的节点。拓扑排序算
    法的步骤为:①初始化集合A、B为空;②将入度为0的节点增加集合A。③从集合A中取元素,将取出的元素增加集合B,并将此元素所指向的全部节点的入度减1。假设有节点的入度减为0,则将其增加到集合A中。④反复步骤③直到结合A为空为止,此时集合B中即为拓扑排序结果。
    #include <iostream>
    /*拓扑排序:
    给定一个有向无环图,把图G中的全部顶点排成一个线性序列,
    使得图中随意边<u,v>。在线性序列中顶点u在顶点v的前面。
    基本思想:
    ①从图中选取入度为0的顶点。并将这些顶点增加队列集合A中;
    ②依次从队列集合A中取元素,将该元素增加到队列集合B中,同一时候将该元素所连接的顶点的入度减1。
    假设顶点的入度减为0,则将该顶点增加到集合A中。
    ③反复②,直到集合A为空。
    */
    typedef char ElemType;
    const int WHITE = 0;
    const int BLACK = 1;
    const int MAX_VERTEX = 30;
    const int MAX_ARC = 900;
    /*边的数据结构*/
    typedef struct arc_node
    {
    	int position;//存储边的还有一个顶点下标
    	int weight;//边的权重
    	struct arc_node *next;//指向下一条边
    }ANode, *pArc;
    /*顶点的数据结构*/
    typedef struct vertex_node
    {
    	ElemType data;
    	pArc first_arc;//指向第一条弧
    }VNode, *pVNode;
    /*图的数据结构*/
    typedef struct graphic_node
    {
    	int vertex_num;//顶点数量
    	int arc_num;//边的数量
    	pVNode vertex[MAX_VERTEX];//用来存放顶点的数组
    }Graphic, *pGNode;
    
    /*辅助数据结构:队列*/
    typedef struct queue_node
    {
    	int data;
    	struct queue_node *next;
    }QNode,*pQNode;
    typedef struct queue
    {
    	pQNode front;
    	pQNode tail;
    }Queue;
    void topologic_sort(Graphic g);
    void create_graphic(pGNode g, int direction);
    /*要想改动内容必须传指针,要想改动内容指向的值能够不传指针*/
    void init_queue(Queue *q);
    bool isempty_queue(Queue q);
    void insert_queue(Queue *q, int e);
    bool delete_queue(Queue *q, int *e);//当删除最后一个元素的时候一定要改动尾部指针
    using namespace std;
    int main()
    {
    	Graphic g;
    	create_graphic(&g,1);
    	topologic_sort(g);
    	return 0;
    }
    
    void create_graphic(pGNode g, int direction)//direction = 0表示创建的是无向图。非0值是有向图
    {
    	cout << "输入顶点数" << endl;
    	cin >> g->vertex_num;
    	cout << "输入边数" << endl;
    	cin >> g->arc_num;
    
    	int i;
    	cout << "输入" << g->vertex_num << "个顶点" << endl;
    	for (i = 0; i < g->vertex_num; i++)
    	{
    		g->vertex[i] = (pVNode)malloc(sizeof(VNode));
    
    		cin >> (g->vertex[i]->data);
    		g->vertex[i]->first_arc = NULL;
    	}
    	cout << "输入" << g->arc_num << "个边和边的权重(比如:输入0 1 20表示下标为0和下标为1的顶点有一条边且权重为20)" << endl;
    	for (i = 0; i < g->arc_num; i++)
    	{
    		int x, y, w;
    		cin >> x >> y >> w;
    
    		pArc temp1 = (pArc)malloc(sizeof(ANode));
    		temp1->position = y;
    		temp1->weight = w;
    		/*将边增加到链接链表中*/
    		temp1->next = g->vertex[x]->first_arc;
    		g->vertex[x]->first_arc = temp1;
    
    		if (direction == 0)//说明是无向图
    		{
    			pArc temp2 = (pArc)malloc(sizeof(ANode));
    			temp2->position = x;
    			temp2->weight = w;
    
    			temp2->next = g->vertex[y]->first_arc;
    			g->vertex[y]->first_arc = temp2;
    		}
    
    	}
    }
    
    void init_queue(Queue *q)
    {
    	/*构造哨兵节点*/
    	pQNode x = (pQNode)malloc(sizeof(QNode));
    	x->next = NULL;
    
    	q->front = q->tail = x;
    }
    
    bool isempty_queue(Queue q)
    {
    	if (q.front->next == NULL)
    		return true;
    	return false;
    }
    
    void insert_queue(Queue *q, int e)
    {
    	pQNode x = (pQNode)malloc(sizeof(QNode));
    	x->next = NULL;
    	x->data = e;
    
    	q->tail->next = x;
    	q->tail = x;
    }
    
    bool delete_queue(Queue *q, int *e)
    {
    	if (isempty_queue(*q))
    		return false;
    
    	pQNode x = q->front->next;
    	*e = x->data;
    	q->front->next = x->next;
    
    	if (x->next == NULL)//假设删除的是最后一个元素
    		q->tail = q->front;
    	free(x);
    	return true;
    }
    
    void topologic_sort(Graphic g)
    {
    	int in[MAX_VERTEX] = { 0 };//用来记录每一个顶点的入度
    	/*统计每一个顶点的入度*/
    	for (int i = 0; i < g.vertex_num;i++)
    	{
    		pArc x = g.vertex[i]->first_arc;
    		while (x != NULL)
    		{
    			in[x->position] += 1;
    			x = x->next;
    		}
    	}
    
    	Queue A, B;
    	init_queue(&A);
    	init_queue(&B);
    
    	/*将入度为0的顶点增加A队列*/
    	for (int i = 0; i < g.vertex_num; i++)
    	{
    		if (in[i] == 0)
    			insert_queue(&A, i);
    	}
    
    	while ( !isempty_queue(A))
    	{
    		int position;
    		delete_queue(&A, &position);
    		insert_queue(&B, position);
    		/*将全部以顶点A为起点的边的其他顶点的入度减1*/
    		pArc y = g.vertex[position]->first_arc;
    		while (y != NULL)
    		{
    			in[y->position] -= 1;
    			if (in[y->position] == 0)
    				insert_queue(&A, y->position);
    			y = y->next;
    		}
    	}
    	/*输出拓扑排序的结果*/
    	while ( !isempty_queue(B) )
    	{
    		int position;
    		delete_queue(&B, &position);
    		cout << g.vertex[position]->data << " ";
    	}
    }

  • 相关阅读:
    大道至简读后感
    机器学习十讲(一)
    第一个TensorFlow的简单例子
    初识深度学习
    如何使用本地的Navicat连接服务器中的Mysql
    阿里云ECS-安装Tomcat
    阿里云ECS-CentOS 8上安装MySQL 8.0
    阿里云ECS--CentOS8安装jdk1.8
    进度报告十(重大技术需求)
    进度报告九 (重大技术需求调研)
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/7373439.html
Copyright © 2011-2022 走看看