拓扑排序代码实现详解

拓扑排序定义:

就是将AOV-网中所有顶点排成一个线性序列,该序列满足:若在AOV-网中顶点A到顶点B有一条路径,则在该线性序列中的顶点A必定在顶点B之前。

如图

则该图有两个拓扑有序序列:

一,A B C D E G I J K  F L H

二,I J K F A L D B C E G H


一,排序大致过程(仅讲上半部分图,上下一样)

遍历过程:


  • 如图(a),先遍历入度为0的顶点,即A,然后去掉以A为弧头的弧,所以对应弧尾的入度减一,当入度变成0,
  • 则入栈,此时因为DB原入度都为1,所以减少后入度为零,所以入栈,因为C原来入度为2,减一后为一,所以不入栈。
  • 此时栈内元素为D B;

  • 如图(b)出栈栈顶元素,即B,然后去掉以B为弧头的弧,所以对应弧尾的入度减一,当入度变成0,
  • 则入栈此时因为C原入度都为1,所以减少后入度为零,所以入栈。
  • 此时栈内元素为D C;

 


  • 如图(c),出栈栈顶元素,即C,然后去掉以C为弧头的弧,所以对应弧尾的入度减一,当入度变成0,则入栈

  • 此时因为EG原入度都为2,所以减少后入度都为一,所以都不入栈
  • 此时栈内元素为D;

 

 


  • 图(d),然后出栈D。。。。。。。。。(都按照上面的过程)

 

看懂上面的图,大致就了解了大致过程

二,实现方法

这一种求最短路径的方法除了需要AOV-网所需的结构体和函数之外,又入了栈和两个数组:

int Indegree[pointMax];        //保存每个顶点的入度数

int topo[pointMax];        //存出度的信息,最后遍历即按照该数组。即可得到结果

eg:如最上面图中,A点的Indegree[ ]为0;B点的Indegree[ ]为1;

 

本程序中图的储存方法类似于十字链表

即每一个顶底都有两个链表,一个该顶点的入度链表,一个该顶点的出度链表
    VtNode *nextVt;           //入度链表下一个结点
    int peace;                //入度下一顶点的值

    VtNode *nextVtt;          //出度链表下一个结点
    int peaceE;               //出度下一顶点的值

定义两个目的是:

首先需要将每一个顶点的入度数存入 Indegree数组中,所以需要用入度链表。

然后找到某一顶点后,需要遍历以该顶点为弧头的所有弧,所以此时还需要一个出度链表。

(这部分可以看我以前关于十字链表编写方法的博客)

 

 

  1. 先构造AOV-网,该过程类似于图的十字链表法类似。
  2. 先将上面新加入的数组进行赋值。
  3. 从入度为零的点进行遍历周围弧,入度为零则入栈。
  4.  然后再出栈,入栈,一直遍历完所有顶点。(上面的图已经说的特别清楚了,可以看上面图)

     (eg:比如A入度为0,以A点为弧头的弧有AB AC AD,则此时B C D 的入度都减一,当减到零时,入栈)。

直到程序结束。

三,代码

(几乎每一部都有相应注释,可以带着注释理解代码)

里面有一些显示的地方,代码运行会看到

#include<iostream>
using namespace std;

#define pointMax 100

struct VtNode               //权值信息
{
	VtNode *nextVt;           //入度链表下一个结点
	int peace;                //入度下一顶点的值

	VtNode *nextVtt;          //出度链表下一个结点
	int peaceE;               //出度下一顶点的值

	int len;
};
struct PoNode                //顶点信息
{
	char data;
	VtNode *firstPo;         //入度
	VtNode *Out;             //出度
};

struct ATgroup
{
	PoNode vertices[pointMax];          //每一个verticse代表一个顶点
	int point, vert;              //point顶点数,vert弧数
};

struct Node
{
	int data;
	Node *next;
};

struct SqStack          //栈
{
	Node *base;         //栈底
	Node *top;          //栈顶
	int data;
};

void Push(SqStack &S, int i)   //入栈
{
	Node *m = new Node;
	m->data = i;
	m->next = S.top;        //入栈过程
	S.top = m;
}

int Pop(SqStack &S)             //出栈
{
	int n = S.top->data;
	S.top = S.top->next;        //出栈过程
	return n;
}


int ATlocate(ATgroup A, char x)          //找到位置
{
	for (int i = 0; i < A.point; i++)           //依次遍历点的信息
	{
		if (A.vertices[i].data == x)       //找到x的位置
		{
			return i;
		}
	}
}

void show(ATgroup &A)                  //显示当前所有点入度出度的顶点
{
	cout << endl;
	for (int i = 0; i < A.point; i++)
	{
		cout << i;
		if (A.vertices[i].firstPo != NULL)          //入度位置
		{
			cout << "    " << A.vertices[i].firstPo->peace << "   ";
		}
		else
			cout << "    -1" << "    ";

		if (A.vertices[i].Out != NULL)              //出度位置
		{
			cout << A.vertices[i].Out->peaceE << endl;
		}
		else
			cout << "    -1" << endl;
	}
}

void CreatAT(ATgroup &A)
{
	cout << "输入邻接矩阵顶点数:";
	cin >> A.point;
	cout << "输入邻接矩阵边数:";
	cin >> A.vert;
	getchar();
	char q[100];
	cout << "输入顶点信息:";
	gets_s(q);
	for (int i = 0; i < A.point; i++)
	{
		A.vertices[i].data = q[i];               //输入顶点值
		A.vertices[i].firstPo = NULL;            //初始化头结点为空
		A.vertices[i].Out = NULL;
	}
	char v1, v2; int m, n; int len;
	for (int i = 0; i < A.vert; i++)             //输入各边,构造邻接表
	{
		cout << "输入第" << i << "条边的依附的两个顶点:";
		cin >> v1 >> v2;
		m = ATlocate(A, v1);                  //确定位置
		n = ATlocate(A, v2);
		//第一个
		VtNode *p1 = new VtNode;
		VtNode *p2 = new VtNode;
		p1->peace = m;                             //入度
		p1->nextVt = A.vertices[n].firstPo;
		A.vertices[n].firstPo = p1;

		p2->peaceE = n;                            //出度
		p2->nextVtt = A.vertices[m].Out;
		A.vertices[m].Out = p2;
	}
	show(A);
}

void FindIn(ATgroup *A, int *in)           //统计所有点的入度数并存入到in数组中
{
	int n = 0;
	for (int i = 0; i < A->point; i++)     //遍历每一个点
	{
		VtNode *p = new VtNode;
		p = A->vertices[i].firstPo;
		while (p != NULL)                  //将入度链表进行遍历
		{
			n++;
			p = p->nextVt;       //下一结点
		}
		in[i] = n;     //存入in数组
		n = 0;
	}
}

void SHOW(int *a, ATgroup *A)            //显示当前所有顶点入度数量还有几个
{
	for (int i = 0; i < A->point; i++)
	{
		cout << a[i] << "  ";
	}
	cout << endl;
}

int M[pointMax] = { 0 };
void TPsort(ATgroup *A, SqStack &S)      //拓扑排序过程
{
	int Indegree[pointMax];
	FindIn(A, Indegree);        //将入度赋值给数组

	for (int i = 0; i < A->point; i++)
	{
		if (Indegree[i] == 0)    //将所有入度等于0的入栈
		{
			cout << "Push=" << i << endl;
			Push(S, i);
		}
	}

	int m = 0;        //统计入度的顶点数
	int n, k;
	int topo[pointMax];        //存出度的信息,最后遍历即按照该数组。

	while (S.base != S.top)      //判断是否遍历完
	{
		cout << endl;
		n = Pop(S);      //栈顶出栈
		cout << "Pop=" << n << endl;
		topo[m] = n;    //存入topo
		m++;
		VtNode* p = new VtNode;
		p = A->vertices[n].Out;        //出度链表的结点
		while (p != NULL)      //遍历出度链表
		{
			k = p->peaceE;     //某结点的位置
			cout << "出度下一结点k=" << k << endl;
			Indegree[k]--;     //将该结点顶点位置入度减一
			//SHOW(Indegree, A);       //显示当前所有点的入度
			if (Indegree[k] == 0)      //当等于0时,入栈
			{
				cout << "Push=" << k << endl;
				Push(S, k);
			}
			p = p->nextVtt;   //下一个
		}
	}
	for (int i = 0; i < m; i++)      //将顶点按照拓扑排序输出
	{
		cout << A->vertices[topo[i]].data;
	}
}

int main()
{
	ATgroup *A = new ATgroup;
	SqStack *S = new SqStack;
	S->top = S->base;
	S->data = pointMax;
	CreatAT(*A);
	TPsort(A, *S);
	system("pause");
}

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章