AOV網與拓撲排序


在一個表示工程的有向圖中,用頂點表示活動,用弧表示活動之間的優先關系,這樣的有向圖為頂點表示活動的網,我們稱之為AOV網(Activity on Vextex Network)。AOV網中的弧表示活動之間存在的某種制約關系,AOV網中不能存在回路,讓某個活動的開始要以自己完成作為先決條件,顯然是不可以的。

設G= { V, E }是一個具有n個頂點的有向圖,V中的頂點序列v1, v2, ...,vn,滿足若從頂點vi到vj有一條路徑,則在頂點序列中頂點vi必在vj之前,則我們稱這樣的頂點序列為一個拓撲排序。

所謂拓撲排序,其實就是對一個有向圖構造拓撲序列的過程。構造時會有兩個結果,如果此網的全部頂點都被輸出,則說明它是不存在(回路)的AOV網;如果輸出頂點少了,哪怕是少了一個,也說明這個網存在環路,不是AOV網。

對AOV網進行拓撲排序的基本思路是:從AOV網中選擇一個入度為0的頂點輸出,然后刪去此頂點,並刪除以此頂點為尾的弧,繼續重復此步驟,直到輸出全部頂點或者AOV網中不存在入度為0的頂點為止。

由於在拓撲排序的過程中,需要刪除頂點,顯然用鄰接表的結構會更加方便,考慮到算法中始終要查找入度為0的頂點,我們可以在原來頂點表結點結構中,增加一個入度域in, 即入度的數字,上面所提到的刪除以某個頂點為尾的弧的操作也是通過將某頂點的鄰接點的in減去1,表示刪除了中間連接的弧。

對於圖7-8-2的第一幅圖AOV網,可以得到如第二幅圖的鄰接表數據結構。


另外,在算法中,還需要輔助的數據結構--棧,用來存儲處理過程中入度為0的點,目的是為了避免每次查找時都要去遍歷頂點表找有沒有入度為0的頂點。

下面來看整體代碼(改編自《大話數據結構》)

 

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
 

#include<iostream>
using namespace std;

#define MAXEDGE 20
#define MAXVEX 14
#define INFINITY 65535

/* 鄰接矩陣結構 */
typedef struct
{
    int vexs[MAXVEX];
    int arc[MAXVEX][MAXVEX];
    int numVertexes, numEdges;
} MGraph;

/* 鄰接表結構****************** */
typedef struct EdgeNode /* 邊表結點  */
{
    int adjvex;    /* 鄰接點域,存儲該頂點對應的下標 */
    int weight;     /* 用於存儲權值,對於非網圖可以不需要 */
    struct EdgeNode *next; /* 鏈域,指向下一個鄰接點 */
} EdgeNode;

typedef struct VertexNode /* 頂點表結點 */
{
    int in; /* 頂點入度 */
    int data; /* 頂點域,存儲頂點信息 */
    EdgeNode *firstedge;/* 邊表頭指針 */
} VertexNode, AdjList[MAXVEX];

typedef struct
{
    AdjList adjList;
    int numVertexes, numEdges; /* 圖中當前頂點數和邊數 */
} graphAdjList, *GraphAdjList;
/* **************************** */

void CreateMGraph(MGraph *G)/* 構建圖 */
{
    int i, j;

    /* printf("請輸入邊數和頂點數:"); */
    G->numEdges = MAXEDGE;
    G->numVertexes = MAXVEX;

    for (i = 0; i < G->numVertexes; i++)/* 初始化圖 */
    {
        G->vexs[i] = i;
    }

    for (i = 0; i < G->numVertexes; i++)/* 初始化圖 */
    {
        for ( j = 0; j < G->numVertexes; j++)
        {
            G->arc[i][j] = 0;
        }
    }

    G->arc[0][4] = 1;
    G->arc[0][5] = 1;
    G->arc[0][11] = 1;
    G->arc[1][2] = 1;
    G->arc[1][4] = 1;
    G->arc[1][8] = 1;
    G->arc[2][5] = 1;
    G->arc[2][6] = 1;
    G->arc[2][9] = 1;
    G->arc[3][2] = 1;
    G->arc[3][13] = 1;
    G->arc[4][7] = 1;
    G->arc[5][8] = 1;
    G->arc[5][12] = 1;
    G->arc[6][5] = 1;
    G->arc[8][7] = 1;
    G->arc[9][10] = 1;
    G->arc[9][11] = 1;
    G->arc[10][13] = 1;
    G->arc[12][9] = 1;

}

/* 利用鄰接矩陣構建鄰接表 */
void CreateALGraph(MGraph G, GraphAdjList *GL)
{
    int i, j;
    EdgeNode *e;

    *GL = (GraphAdjList)malloc(sizeof(graphAdjList));

    (*GL)->numVertexes = G.numVertexes;
    (*GL)->numEdges = G.numEdges;
    for(i = 0; i < G.numVertexes; i++) /* 讀入頂點信息,建立頂點表 */
    {
        (*GL)->adjList[i].in = 0;
        (*GL)->adjList[i].data = G.vexs[i];
        (*GL)->adjList[i].firstedge = NULL;     /* 將邊表置為空表 */
    }

    for(i = 0; i < G.numVertexes; i++) /* 建立邊表 */
    {
        for(j = 0; j < G.numVertexes; j++)
        {
            if (G.arc[i][j] == 1)
            {
                e = (EdgeNode *)malloc(sizeof(EdgeNode));
                e->adjvex = j;                  /* 鄰接序號為j  */
                e->next = (*GL)->adjList[i].firstedge;  /* 將當前頂點上的指向的結點指針賦值給e */
                (*GL)->adjList[i].firstedge = e;        /* 將當前頂點的指針指向e  */
                (*GL)->adjList[j].in++; /* 注意這里是j */

            }
        }
    }

}
/* 拓撲排序,若GL無回路,則輸出拓撲排序序列並返回1,若有回路返回0。 */
bool TopologicalSort(GraphAdjList GL)
{
    EdgeNode *pe;
    int i, k, gettop;
    int top = 0;/* 用於棧指針下標  */
    int count = 0;/* 用於統計輸出頂點的個數  */
    /* 建棧將入度為0的頂點入棧  */
    int *stack = (int *)malloc(sizeof(GL->numVertexes * sizeof(int)));

    for (i = 0; i < GL->numVertexes; i++)
        if (0 == GL->adjList[i].in)
            stack[++top] = i;/* 將入度為0的頂點入棧 */

    while (top != 0)
    {
        gettop = stack[top--];
        cout << GL->adjList[gettop].data << " -> ";
        count++;  /* 輸出i號頂點,並計數 */
        for (pe = GL->adjList[gettop].firstedge; pe; pe = pe->next)
        {
            k = pe->adjvex;
            /* 將i號頂點的鄰接點的入度減1,如果減1后為0,則入棧 */
            if (!--GL->adjList[k].in)
                stack[++top] = k;
        }
    }
    cout << endl;
    if (count < GL->numVertexes)
        return false;
    else
        return true;
}

int main(void)
{
    MGraph MG;
    GraphAdjList GL;
    CreateMGraph(&MG);
    CreateALGraph(MG, &GL);
    if (TopologicalSort(GL))
        cout << "It's a AOV network" << endl;
    else
        cout << "It's not a AOV network" << endl;

    return 0;
}

 

輸出為:


算法的代碼相比較最小生成樹和最短路徑是比較好理解的,注釋也比較清楚,這里就不費口舌了,如下圖7-8-4是將結點v3被刪除的模擬圖,其他依次

被刪除的結點情形類似,可類推。需要注意的是上面有個通過鄰接矩陣(事先確定)來生成鄰接表的函數CreateALGraph,因為是有向圖,所以針對一

條邊只插入一次EdgeNode, 且初始化in時注意是入度,即 (*GL)->adjList[j].in++;  /* 注意這里是j */  另外創建鄰接矩陣的函數CreateMGraph中因為是有

向圖,故矩陣並不是對稱的,需要注意。另外也不是網圖,故只用1表示弧存在,0表示弧不存在。

當然程序輸出的結果並不是唯一的一種拓撲排序方案。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM