Tabla de contenido
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.
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 :
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
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