[Estructura de datos] Clasificación topológica de gráfico acíclico dirigido (AOV-net) (lenguaje C)

1. Secuencia topológica

Un gráfico acíclico dirigido es un gráfico dirigido sin ciclos. Los gráficos acíclicos dirigidos se pueden utilizar para describir el proceso de un proyecto o sistema, como un dibujo de construcción de un proyecto, un gráfico de restricciones entre cursos para estudiantes, etc.
Un gráfico acíclico dirigido que usa vértices para representar actividades y arcos para representar la relación de prioridad entre actividades se denomina red de actividad representada por vértice , o AOV-net para abreviar .
Secuencia topológica : En un grafo dirigido G = (V, {E}), la secuencia lineal (v1, v2, v3, ..., vn) de vértices en V se denomina secuencia topológica. Si esta secuencia satisface la condición: para dos vértices cualesquiera vi y vj en la secuencia, hay un camino de vi a vj en G, entonces vi debe estar dispuesto antes de vj en la secuencia.
secuencia topológica
Las características de AOV-net :
① Si vi es la actividad anterior de vj y vj es la actividad anterior de vk, entonces vi debe ser la actividad anterior de vk, es decir, la relación anterior es transitiva.
La secuencia topológica de AOV-net no es única . Otra secuencia topológica del gráfico acíclico dirigido que se muestra arriba es: C1, C2, C3, C8, C4, C5, C9, C7, C6. La idea básica de
la clasificación topológica (Ordenación topológica) : ① Seleccione una salida de nodo sin predecesor del gráfico dirigido; ② Elimine este nodo y el borde que comienza desde él; ③ Repita ① y ② hasta que no haya predecesor ④ Si el número de nodos de salida es menor que el número de vértices en el gráfico dirigido en este momento, significa que hay bucles en el gráfico dirigido; de lo contrario, el orden de los vértices de salida es una secuencia topológica . Ejemplo :





Proceso de implementación

2. Implementación de clasificación topológica (tomando la lista de adyacencia como ejemplo)

2.1 Idea básica

Un vértice con un grado de entrada de 0 es un vértice sin predecesor Para la estructura de lista de adyacencia, se puede adjuntar una matriz en grado[] para almacenar el grado de entrada de cada vértice, así que: ① Encuentre el nodo sin un predecesor en G——busque el grado[i]
como el vértice i de 0;
② Elimine todos los arcos que comiencen desde i——para todos los vértices k adyacentes detrás del vértice i, el grado[k] correspondiente se reducirá en 1; (Nota:
si el almacenamiento la estructura es una matriz de adyacencia, luego
① Encuentre los nodos sin predecesores en G: encuentre las columnas con todos los valores 0 en la matriz de adyacencia;
② Elimine todos los arcos que comienzan desde i: establezca todas las filas correspondientes a i en la matriz en 0 ;)

Para evitar la detección repetida de vértices cuyo grado de entrada sea 0, se puede configurar una pila auxiliar. Si el grado de entrada de un vértice se reduce a 0, se insertará en la pila. Cada vez que se genera un vértice, se eliminará de la pila, es decir, se abrirá la pila.

2.2 Implementación completa del código y ejecución de resultados

# include<stdio.h>
# include<malloc.h>
# define MAX_VERTEX_NUM 20
# define TRUE 1
# define FALSE 0

/*图的邻接表表示法*/
typedef char VertexData;
//弧结点结构
typedef struct ArcNode {
    
    
	int adjvex;								//该弧指向顶点的位置
	struct ArcNode* nextarc;				//指向下一条弧的指针
}ArcNode;
//表头结点结构
typedef struct VertexNode {
    
    
	VertexData data;						//顶点数据
	ArcNode* firstarc;						//指向该顶点的第一条弧的指针
}VertexNode;
//邻接表结构
typedef struct {
    
    
	VertexNode vertex[MAX_VERTEX_NUM];
	int vexnum, arcnum;						//图的顶点数和弧数
}AdjList;

/*求顶点位置*/
int LocateVertex(AdjList* G, VertexData v) {
    
    
	int k;
	for (k = 0; k < G->vexnum; k++) {
    
    
		if (G->vertex[k].data == v)
			break;
	}
	return k;
}

/*创建有向图的邻接表*/
int CreateAdjList(AdjList* G) {
    
    
	int i, j, k;
	VertexData v1, v2;
	ArcNode* p;
	printf("输入图的顶点数和弧数:");				//输入图的顶点数和弧数
	scanf("%d%d", &G->vexnum, &G->arcnum);
	printf("输入图的顶点:");
	for (i = 0; i < G->vexnum; i++) {
    
    			//输入图的顶点,初始化顶点结点
		scanf(" %c", &(G->vertex[i].data));
		G->vertex[i].firstarc = NULL;
	}
	for (k = 0; k < G->arcnum; k++) {
    
    
		printf("输入第%d条弧的两个顶点:", k + 1);
		scanf(" %c %c", &v1, &v2);				//输入一条弧的两个顶点
		i = LocateVertex(G, v1);
		j = LocateVertex(G, v2);
		p = (ArcNode*)malloc(sizeof(ArcNode));	//申请新弧结点
		p->adjvex = j;
		p->nextarc = G->vertex[i].firstarc;
		G->vertex[i].firstarc = p;
	}
}

/*顺序栈的存储结构,辅助栈*/
typedef struct {
    
    
	int elem[MAX_VERTEX_NUM];			//用于存放栈中元素的一维数组
	int top;							//存放栈顶元素的下标,top为-1表示空栈
}SeqStack;

/*初始化顺序栈*/
void InitStack(SeqStack* S) {
    
    
	S->top = -1;
}

/*判空*/
int IsEmpty(SeqStack* S) {
    
    
	if (S->top == -1)					//栈为空
		return TRUE;
	else
		return FALSE;
}

/*顺序栈进栈*/
int Push(SeqStack* S, int x) {
    
    
	if (S->top == MAX_VERTEX_NUM - 1)	//栈已满
		return FALSE;
	S->top++;
	S->elem[S->top] = x;				//x进栈
	return TRUE;
}

/*顺序栈出栈*/
int Pop(SeqStack* S) {
    
    
	if (S->top == -1)					//栈为空
		return FALSE;
	S->top--;
	return TRUE;
}

int indegree[MAX_VERTEX_NUM];			//存放各顶点入度

/*求各顶点入度算法*/
void FindID(AdjList G) {
    
    
	int i;
	ArcNode* p;
	for (i = 0; i < G.vexnum; i++)
		indegree[i] = 0;
	for (i = 0; i < G.vexnum; i++) {
    
    
		p = G.vertex[i].firstarc;
		while (p != NULL) {
    
    
			indegree[p->adjvex]++;
			p = p->nextarc;
		}
	}
}

/*拓扑排序算法*/
int TopoSort(AdjList G) {
    
    
	int i, count = 0, k;
	SeqStack S;
	ArcNode* p;
	FindID(G);							//求各顶点入度
	InitStack(&S);						//初始化辅助栈
	for (i = 0; i < G.vexnum; i++) {
    
    
		if (indegree[i] == 0)
			Push(&S, i);				//将入度为0的顶点入栈
	}
	while (!IsEmpty(&S)) {
    
    
		i = S.elem[S.top];
		Pop(&S);
		printf("%c ", G.vertex[i]);
		count++;
		p = G.vertex[i].firstarc;
		while (p != NULL) {
    
    
			k = p->adjvex;
			indegree[k]--;				//i号顶点的每个邻接点的入度减1
			if (indegree[k] == 0)
				Push(&S, k);			//若入度减为0则入栈
			p = p->nextarc;
		}
	}
	if (count < G.vexnum) {
    
    
		printf("该图存在回路!\n");
		return FALSE;
	}
	else
		return TRUE;
}

int main() {
    
    
	AdjList G;
	CreateAdjList(&G);
	printf("\n拓扑排序:");
	TopoSort(G);
	return 0;
}

Resultados de la operación
resultado de la operación
Referencia: Geng Guohua "Estructura de datos: descrita en lenguaje C (segunda edición)"

Para obtener más contenido de estructura de datos, siga mi columna "Estructura de datos" : https://blog.csdn.net/weixin_51450101/category_11514538.html?spm=1001.2014.3001.5482

Supongo que te gusta

Origin blog.csdn.net/weixin_51450101/article/details/123018532
Recomendado
Clasificación