拓扑排序(基于邻接表实现)

本文详细介绍了如何使用C++实现有向无环图(DAG)的拓扑排序,包括创建图、显示图、计算各顶点入度以及拓扑排序算法的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <iostream>
#include <stack> 
using namespace std;
#define MAX 100

typedef char VertexType; 

typedef struct ArcNode {
	 int adjvex;    				//邻接点域,存储该弧指向顶点的下标 (终点) 
	 struct ArcNode *next;			//指向下一条弧的指针 
	 int weight;					//权重 
}ArcNode;		//边结构 

typedef struct VertexNode {
	VertexType data;				//数据域 
	ArcNode *firstArc;				//指向第一条依附该顶点的弧的指针 	
}VertexNode,AdjVerList[MAX];

typedef struct {
	AdjVerList vertices;				//顶点集		
	int vexnum,arcnum; 				//图的顶点数和弧数
}ALGraph;		//图结构

int indegree[MAX];				//每个顶点对应的入度数组 

void CreateALGraph(ALGraph *G);
void Display(ALGraph *G);
int TopoSort(ALGraph *G);
//a b c d e f g h i 
/*
a c 0
a h 0
b c 0
b d 0
b e 0
c d 0
d f 0
d g 0
e f 0
h i 0
i g 0
*/
int main()
{
	ALGraph G;	
	CreateALGraph(&G);
	//Display(&G);
	TopoSort(&G);
	return 0;
}

//求顶点位置函数
int LocateVex(ALGraph *G,VertexType v)
{
    int i;
    for(i=0;i<G->vexnum;i++)
    {
        if(G->vertices[i].data == v)
            return i;
    }
    return -1;
}

//有向无环图 
void CreateALGraph(ALGraph *G)
{
    VertexType v1,v2;
    int w;
    ArcNode *Arc;

    cout<<"请输入顶点数和边数:";
    cin>>G->vexnum>>G->arcnum;


    cout<<"请输入各顶点的数据:";     
    for(int i=0;i<G->vexnum;i++){
        cin>>G->vertices[i].data;
        G->vertices[i].firstArc = NULL;     //顶点的边表设为空
    }

    cout<<"请依次输入"<<G->arcnum<<"组边对应的两个顶点以及权值,以空格分割:"<<endl;
    for(int k=0;k<G->arcnum;k++) {
		cin>>v1>>v2>>w;
        int i = LocateVex(G,v1);
        int j = LocateVex(G,v2);  
        Arc = new ArcNode;				//新建边 
        Arc->adjvex = j;
        Arc->weight = w;
        Arc->next = G->vertices[i].firstArc;        
        G->vertices[i].firstArc = Arc;
    }
}

void Display(ALGraph *G)
{
    ArcNode *p;
    cout<<"编号,  顶点,   相邻边的顶点\n";
    for(int i=0;i<G->vexnum;i++)
    {
        cout<<i<<"\t"<<G->vertices[i].data;
        for(p=G->vertices[i].firstArc;p!=NULL;p=p->next)
            cout<<"\t"<<p->adjvex;
        cout<<endl;
    }
}


//求各顶点的入度(遍历整个邻接表)
void FindIndegree(ALGraph *G)
{
	int i;
	ArcNode *p;
    //初始化每个顶点的入度为0
	for(i=0;i<G->vexnum;i++)
        indegree[i] = 0; 

    for(i=0;i<G->vexnum;i++)
    {
        p = G->vertices[i].firstArc;
        while(p)
        {
        	//将每一个临接到的点(终点)自增 
            indegree[p->adjvex]++;
            p = p->next;
        }

        //cout<<i<<"元素的入度为:"<<indegree[i]<<endl;
    } 
} 

//返回值的失败与否代表该有向图是否存在回路
//拓扑排序 
int TopoSort(ALGraph *G)
{
	cout<<"该有向图的一种拓扑排序结果为:"<<endl; 
	stack<int> s;	//设置辅助栈,避免重复检测入度为0的顶点
	ArcNode *p;
	int i,k;
	FindIndegree(G);
	
	for(i=0;i<G->vexnum;i++)
	{
		//将入度为0的顶点入栈
		if(indegree[i]==0)
			s.push(i); 
	}
	
	int count = 0;
	while(!s.empty())
	{
		i = s.top();
		s.pop();
		cout<<G->vertices[i].data<<" "; 	//将栈顶出栈并打印
		count++;							//统计已输出的顶点数 
		
		p = G->vertices[i].firstArc;
		while(p!=NULL)
		{
			k = p->adjvex;
			indegree[k]--;					//i号顶点已出栈,所以将i号顶点的每个邻接点的入度自减 
			if(indegree[k]==0)
				s.push(k);					//如果入度减为0,则入栈
			p = p->next; 
		}
	}
	
	if(count<G->vexnum)
		return -1;							//存在回路 
	else
		return 0;
}

拓扑排序是一种有向无环图 (DAG) 中节点的线性排列,它满足对于每条有向边 (u, v),节点 u 在排序后的列表中出现在节点 v 之前。在基于邻接矩阵的实现中,C语言通常会采用以下几个步骤: 1. **构建邻接矩阵**:使用二维数组表示图,其中行代表源节点,列代表目标节点,值非零表示有边。 ```c int graph[vertices][vertices]; // 邻接矩阵 ``` 2. **计算入度**:遍历矩阵,统计每个节点的入度(指向它的边的数量)。可以使用哈希表简化这一过程。 3. **创建拓扑排序队列**:从所有入度为0的节点开始,将它们加入队列。同时,更新入度记录。 4. **拓扑排序循环**: - 取队首节点,并移除。 - 对其所有邻居减1入度,如果邻居入度变为0,则加入队列。 - 重复此过程,直到队列为空。 5. **检查有无环**:如果在处理过程中发现某个节点的入度始终大于0,说明存在环,此时无法完成拓扑排序。 6. **返回结果**:如果所有节点都出队了,那么排好序的节点即为拓扑排序的结果。如果没有环,这个序列就表示了一个合法的拓扑顺序。 ```c void topologicalSort(int vertices, int edges[], int adjMatrix[]) { // ... 实现上述步骤 ... // 检查并返回结果 if (result == false) { printf("图中有环,无法进行拓扑排序.\n"); } else { for (int i = 0; i < vertices; i++) { printf("%d ", sorted[i]); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值