寫在前面:這篇文章在一週前就應該發的,後來因爲騰訊面試拖到現在,雖然現在下動車也有一兩個小時了,但是感覺自己好像還在路上顛簸。昨天去騰訊深圳總部面試,深圳總部啊!馬爸爸在的地方!可惜跪了。可能是因爲我主要偏軟件開發然後投了運維簡歷投偏了吧,騰訊的面試還真是玄學呢!我也感受到自己已經達到了技術瓶頸,回爐修煉~
圖的這一章節終於快複習完了,加油加油!今天要總結的是拓撲排序,是基於AOV網的。這個拓撲排序與我們之前熟知的快速排序啊,冒泡排序啊有異同點。相同的地方是它們都能把一組數排序成有序序列。而不同的地方也恰恰在這個有序上,拓撲排序中的有序並不是什麼從大到小,或者是從小到大;而是一種先後的邏輯上的關係,具有一定的實際意義。
知識儲備:AOV網
AOV網是一個英文縮寫,全稱是Activity On Vertex Network,即活動在頂點上的網。是一個有向不帶權重的圖,並且沒有迴路。可以用它來描述工程中各個活動的先後次序,如工業上的流程,如下圖
要製作一個產品,首先要去尋找原料,然後生成出3個部件,最後獲得成品。這個就是一個普通的生產過程,如果我們用一條有向線段從成品指向了原料,那麼這個圖中就出現了迴路,也就是出現環了。這樣的話,剛生產出來的產品卻又變成了原料,這顯然是違背【生產產品】這個工程的實際意義的。
拓撲排序看上去很抽象,其實實現起來還是十分容易的。算法思路如下:
1、 選擇圖中入度爲0的頂點,輸出
2、 刪除這個頂點引出的所有邊
3、 重複步驟【1】、【2】,直到圖中所有頂點輸出爲止(也就是不再有入度爲0的點)
算法準備:
1、 圖的鄰接矩陣存儲結構(其實用鄰接表也是可以的)
2、 一個visit數組,用於標識某個頂點是否被輸出過
下面先用手工的方式演示一下拓撲排序的算法過程(基於鄰接矩陣)
我們的用例圖如A所示,鄰接矩陣在右下角,圖的頂點編號從1開始。
1、初始化visit數組,默認全爲0
2、 我們知道,在圖的鄰接矩陣存儲結構中,每一行之和代表這個頂點的出度,每一列之和代表一個頂點的入度。所以,我們選擇鄰接矩陣中第一次出現的,列和全爲0的點,顯然是編號爲1的頂點。將visit[1]的值改爲1,並且將這個頂點輸出。
3、 刪除頂點1,以及頂點1引出的所有邊(出度),這樣,就由圖A變爲圖B。對應的矩陣操作就是將第1行全變爲0
4、繼續尋找鄰接矩陣中列和爲0的點,此時圖中第1列和第2列都是符合條件的,但是頂點1已經訪問過了,所以選擇頂點2,即第二列。將visit[2]的值改爲1,並輸出
5、刪除頂點2以及它所引出的邊,即將鄰接矩陣中第2行全變爲0。由圖B變爲圖C
6、 如此往復,直到visit數組全變爲1爲止。
最後輸出序列爲:1 2 3 4 5
需要注意的是,拓撲排序的序列不是唯一的,我這邊是採用數組,如果採用棧的話就不一定是這個序列了。
拓撲排序的要求是圖不能有迴路,如果圖中帶環,會導致排序失敗,因爲圖會在某一個時刻找不到入度爲0的點,所以拓撲排序的一個應用是檢測圖中是否帶有迴路。
下面上代碼:這段代碼帶有圖是否有環的檢測
1、圖的結構體定義(n爲頂點數、e爲邊數)
#define Max 100
typedef struct graph *Graph;
typedef struct graph
{
int data[Max][Max];
int n , e;
}graph;
//data表示鄰接矩陣,最大100 x 100
//n表示圖有n個頂點,e表示有e條邊
2、拓撲排序代碼(鄰接矩陣+數組實現)
int TopSort(Graph g)
{
int v , i , j , count , n = 0;
int *visit = (int*)malloc(sizeof(int) * (g->n + 1));
//初始化visit數組
for(i = 1 ; i <= g->n ; i++)
{
visit[i] = 0;
}
while(n != g->n)
{
//遍歷鄰接矩陣,尋找入度爲0的點,若找到,退出循環
for(i = 1 ; i <= g->n ; i++)
{
count = 0;
for(j = 1 ; j <= g->n ; j++)
{
count += g->data[j][i];
}
if(count == 0 && visit[i] == 0)
{
v = i;
n++;
visit[v] = 1;
break;
}
}
//如果某一時刻遍歷完全部的鄰接矩陣也沒有找到入度爲0的點
//此時,i與j指向最後一個元素,勢必相等,表示發現環。
if(i == j)//發現環
{
return 1;
}
printf("%d ",v);
//將入度爲0的點v所在的那一行全部變成0,因爲列已經全0,表示刪除該點
for(i = 1 ; i <= g->n ; i++)
{
g->data[v][i] = 0;
}
}
return 0;
}
最後附上一張騰訊招聘現場吧~勉勵自己繼續加油!