拓補排序簡介
對一個有向無環圖(Directed Acyclic Graph簡稱DAG)G進行拓撲排序,是將G中所有頂點排成一個線性序列,使得圖中任意一對頂點u和v,若邊(u,v)∈E(G),則u在線性序列中出現在v之前
首先需要知道一個概念:入度。
通常指有向圖中某點作爲圖中邊的終點的次數之和。
比如:
節點 | A | B | C | D | E |
---|---|---|---|---|---|
入度 | 0 | 1 | 1 | 1 | 3 |
實現過程
對圖進行深度優化搜索,將頂點放入數組中,改變與之連接的下個節點的入度。
圖片取自:拓撲排序(Topological Sorting)
代碼實現
核心代碼:
BOOLEAN isInTop(VTYPE *topNum, int length, VTYPE key) {
for (int i = 0; i < length; i++) {
if (topNum[i] == key) {
return TRUE;
}
}
return FALSE;
}
int degreePos(AdjGraphPtr adj, VTYPE *topNum , int length) {
int pos = -1;
for (int i = 0; i < adj->vNum; i++) {
if (adj->vertexList[i]->degree == 0) {
if (isInTop(topNum, length, adj->vertexList[i]->v) == FALSE) {
pos = i;
return pos;
}
}
}
return pos;
}
int getEmptyPos(VTYPE *topNum, int length) {
//獲得未使用的位置
for (int i = 0; i < 5; i++) {
if (topNum[i] == 0) {
return i;
}
}
return -1;
}
int dfs(AdjGraphPtr adj, VTYPE *topNum, int length, int pos) {
EdgePtr tmp = adj->vertexList[pos]->firstEdge;
while (tmp != NULL) {
VTYPE w = tmp->w;
int w_pos = getVertexPos(adj, w);
adj->vertexList[w_pos]->degree--;
if (adj->vertexList[w_pos]->degree == 0)
continue;
if (isInTop(topNum, length, w) == FALSE) {
int emptyPos = getEmptyPos(topNum, length);
if(emptyPos != -1)
topNum[emptyPos] = w;
}
dfs(adj, topNum, length, w_pos);
tmp = tmp->next;
}
}
void topSort(AdjGraphPtr adj, int length) {
VTYPE topNum[5];
for (int i = 0; i < length; i++) {
topNum[i] = 0;
}
for (int i = 0; i < length; i++) {
int pos = degreePos(adj, topNum, length);
if (pos == -1) {
return;
}
int emptyPos = getEmptyPos(topNum, length);
if (emptyPos != -1)
topNum[emptyPos] = adj->vertexList[pos]->v;
dfs(adj, topNum, length, pos);
}
}
完整代碼:
#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <assert.h>
#define MAXVEX 100
#define MAXNUM 10
#define INFINITE 65525
#define VTYPE char
#define QUETYPE EdgePtr
#define SORTTYPE int
#define BOOLEAN int
#define TRUE 1
#define FALSE 0
typedef struct EdgeNode {
VTYPE v;
VTYPE w;
int weight;
struct EdgeNode *next;
} Edge, *EdgePtr;
typedef struct VertexNode {
VTYPE v;
int degree;
EdgePtr firstEdge;
} Vertex, *VertexPtr;
typedef struct {
VertexPtr vertexList[MAXVEX];
int vNum;
int eNum;
} AdjGraph, *AdjGraphPtr;
void freeAdj(AdjGraphPtr a);
EdgePtr createEdgeNode(VTYPE v, VTYPE w, int weight);
int getVertexPos(const AdjGraphPtr m, const VTYPE key);
void insertVertex(AdjGraphPtr adj, const VTYPE key);
void insertEdge(AdjGraphPtr adj, VTYPE a, VTYPE b, int weight);
void addEdge(AdjGraphPtr adj, VTYPE a, VTYPE b, int weight);
AdjGraphPtr createAdjGraph(VTYPE *v, const int v_length, int *e, const int e_length_1, const int e_length_2);
AdjGraphPtr createDirectedGraph(VTYPE *v, const int v_length, int *e, const int e_length_1, const int e_length_2);
void print(int *a, int length);
BOOLEAN isInTop(VTYPE *topNum, int length, VTYPE key) {
for (int i = 0; i < length; i++) {
if (topNum[i] == key) {
return TRUE;
}
}
return FALSE;
}
int degreePos(AdjGraphPtr adj, VTYPE *topNum , int length) {
int pos = -1;
for (int i = 0; i < adj->vNum; i++) {
if (adj->vertexList[i]->degree == 0) {
if (isInTop(topNum, length, adj->vertexList[i]->v) == FALSE) {
pos = i;
return pos;
}
}
}
return pos;
}
int getEmptyPos(VTYPE *topNum, int length) {
//獲得未使用的位置
for (int i = 0; i < 5; i++) {
if (topNum[i] == 0) {
return i;
}
}
return -1;
}
int dfs(AdjGraphPtr adj, VTYPE *topNum, int length, int pos) {
EdgePtr tmp = adj->vertexList[pos]->firstEdge;
while (tmp != NULL) {
VTYPE w = tmp->w;
int w_pos = getVertexPos(adj, w);
adj->vertexList[w_pos]->degree--;
if (adj->vertexList[w_pos]->degree == 0)
continue;
if (isInTop(topNum, length, w) == FALSE) {
int emptyPos = getEmptyPos(topNum, length);
if(emptyPos != -1)
topNum[emptyPos] = w;
}
dfs(adj, topNum, length, w_pos);
tmp = tmp->next;
}
}
void topSort(AdjGraphPtr adj, int length) {
VTYPE topNum[5];
for (int i = 0; i < length; i++) {
topNum[i] = 0;
}
for (int i = 0; i < length; i++) {
int pos = degreePos(adj, topNum, length);
if (pos == -1) {
return;
}
int emptyPos = getEmptyPos(topNum, length);
if (emptyPos != -1)
topNum[emptyPos] = adj->vertexList[pos]->v;
dfs(adj, topNum, length, pos);
}
}
void main() {
int e[6][3] = {
{ 'A', 'B', 3 },
{ 'B', 'D', 1 },
{ 'B', 'E', 5 },
{ 'B', 'C', 6 },
{ 'D', 'E', 7 },
{ 'C', 'E', 6 },
};
const int e_length_1 = 6;
const int e_length_2 = 3;
VTYPE v[5] = { 'A','B','C','D','E' };
const int v_length = 5;
AdjGraphPtr adj = createDirectedGraph(v, v_length, e, e_length_1, e_length_2);
topSort(adj, v_length);
freeAdj(adj);
}
void freeAdj(AdjGraphPtr a) {
for (int i = 0; i < a->vNum; i++) {
if (a->vertexList[i]->firstEdge != NULL) {
EdgePtr tmp = a->vertexList[i]->firstEdge;
while (tmp->next != NULL) {
EdgePtr t = tmp;
tmp = tmp->next;
free(t);
}
free(tmp);
}
free(a->vertexList[i]);
}
free(a);
}
EdgePtr createEdgeNode(VTYPE v, VTYPE w, int weight) {
EdgePtr a = (EdgePtr)malloc(sizeof(Edge));
memset(a, 0, sizeof(Edge));
a->v = v;
a->w = w;
a->weight = weight;
a->next = NULL;
return a;
}
int getVertexPos(const AdjGraphPtr m, const VTYPE key) {
for (int i = 0; i < m->vNum; i++) {
if (m->vertexList[i]->v == key)
return i;
}
return -1;
}
void insertVertex(AdjGraphPtr adj, const VTYPE key) {
for (int i = 0; i < adj->vNum; i++) {
if (adj->vertexList[i]->v == key)
return;
}
VertexPtr vNode = (VertexPtr)malloc(sizeof(Vertex));
memset(vNode, 0, sizeof(Vertex));
vNode->v = key;
vNode->firstEdge = NULL;
adj->vertexList[adj->vNum] = vNode;
adj->vNum++;
}
void insertEdge(AdjGraphPtr adj, VTYPE a, VTYPE b, int weight) {
int pos_a = getVertexPos(adj, a);
EdgePtr avex = createEdgeNode(a, b, weight);
if (adj->vertexList[pos_a]->firstEdge == NULL) {
adj->vertexList[pos_a]->firstEdge = avex;
}
else {
EdgePtr tmp = adj->vertexList[pos_a]->firstEdge;
while (tmp->next != NULL) {
tmp = tmp->next;
}
tmp->next = avex;
}
int pos_b = getVertexPos(adj, b);
adj->vertexList[pos_b]->degree++;
}
void addEdge(AdjGraphPtr adj, VTYPE a, VTYPE b, int weight) {
insertEdge(adj, a, b, weight);
insertEdge(adj, b, a, weight);
adj->eNum++;
}
AdjGraphPtr createAdjGraph(VTYPE *v, const int v_length, int *e, const int e_length_1, const int e_length_2) {
AdjGraphPtr adj = (AdjGraphPtr)malloc(sizeof(AdjGraph));
memset(adj, 0, sizeof(AdjGraph));
for (int i = 0; i < v_length; i++) {
insertVertex(adj, v[i]);
}
for (int i = 0; i < e_length_1; i++) {
VTYPE a = *(e + e_length_2 * i + 0);
VTYPE b = *(e + e_length_2 * i + 1);
int weight = *(e + e_length_2 * i + 2);
addEdge(adj, a, b, weight);
}
return adj;
}
AdjGraphPtr createDirectedGraph(VTYPE *v, const int v_length, int *e, const int e_length_1, const int e_length_2) {
AdjGraphPtr adj = (AdjGraphPtr)malloc(sizeof(AdjGraph));
memset(adj, 0, sizeof(AdjGraph));
for (int i = 0; i < v_length; i++) {
insertVertex(adj, v[i]);
}
for (int i = 0; i < e_length_1; i++) {
VTYPE a = *(e + e_length_2 * i + 0);
VTYPE b = *(e + e_length_2 * i + 1);
int weight = *(e + e_length_2 * i + 2);
insertEdge(adj, a, b, weight);
}
adj->eNum++;
return adj;
}
void print(int *a, int length) {
for (int i = 0; i < length; i++) {
printf("%d ", a[i]);
}
putchar('\n');
}