1. 程式人生 > >演算法精解----17、圖的應用

演算法精解----17、圖的應用

知識小結:
(1)連結串列可以動態擴充套件和收縮,這是較陣列的優點
(2)網際網路建模,關節點代表單點故障源,如果該點出錯則系統無法通訊。因此在設計保持長時間連線的大型網路架構時,很重要的一點就是保證網路中沒有關節點。
(3)有向圖很適合狀態機建模
(4)超圖:包含超邊,即可以連線任意數量頂點的邊
(5)多重圖:允許在相同的兩個頂點間有多條邊存在
(6)鄰接矩陣表示法:V*V階矩陣,V 頂點個數,如果頂點u,v之間存在一條邊,則在矩陣[u,v]處設定一個標誌

應用:
1、計算網格跳數-採用廣度優先搜尋確定節點之間的最小跳數
這裡寫圖片描述
2、廣度優先搜尋程式碼
資料結構
這裡的BfsVertex,即AdjList中*vertex指向的內容。包含節點資料、顏色、跳數。

typedef struct BfsVertex_{
    void *data;
    VertexColor color;
    int hops;
}BfsVertex;
//start:指定起始點,hops:返回起始點能夠到達的所有點
int bfs(Graph *graph, BfsVertex *start, List *hops)
{
    Queue queue;
    AdjList *adjlist, *clr_adjlist;
    BfsVertex *clr_vertex, *adj_vertex;
    LIST_ELEMENT *element, *
member; //找到起點塗灰,跳數為0,其餘圖白,跳數為-1 for(element = list_head(graph->adjlists); element != NULL; element = list_next(element)) { clr_vertex = ((AdjList *)element->data)->vertex; if(graph->match(clr_vertex, start)) { clr_vertex->color = gray; clr_vertex->
hops = 0; } else { clr_vertex->color = white; clr_vertex->hops = -1; } } queue_init(&queue,NULL); //找到與起點對應的資訊存於clr_adjlist if(graph_adjlist(graph, start, &clr_adjlist) != 0) { queue_destroy(&queue); return -1; } //起點入佇列 if(queue_enqueue(&queue, clr_adjlist) != 0) { queue_destroy(&queue); return -1; } while(queue_size(&queue) > 0) { //起點出佇列,把起點的鄰接點塗灰,hops加1如佇列 //之前已經塗灰的不會如佇列,這就避免節點重複 adjlist = queue_peek(&queue); for(member = list_head(&adjlist->adjacent); member != NULL; member = list_next(element)) { adj_vertex = member->data; if(graph_adjlist(graph, adj_vertex, &clr_adjlist) != 0) { queue_destroy(&queue); return -1; } clr_vertex = clr_adjlist->vertex; if(clr_vertex->color == white) { clr_vertex->color = gray; clr_vertex->hops = ((BfsVertex *)(adjlist->vertex)->hops + 1); if(queue_enqueue(&queue, clr_adjlist) != 0) { queue_destroy(&queue); return -1; } } } //出佇列一個二級節點,塗黑,以這個圖黑的節點取代起始節點的地位,再次尋找它的鄰接點入佇列(先進先出) //然後再出第二個二級節點,塗黑重複 if(queue_dequeue(&queue, (void **)&adjlist) == 0) { ((BfsVertex *)adjlist->vertex)->color = black; } else { queue_destroy(&queue); return -1; } } queue_destroy(&queue); list_init(hops, NULL); //把跳數不為-1的點(由起始點能到達的點)放到連結串列hops中 for(element = list_head(graph->adjlists); element != NULL; element = list_next(element)) { clr_vertex = ((AdjList *)element->data)->vertex; if(clr_vertex->hops != -1) { if(list_ins_next(hops, list_tail(hops), clr_vertex) != 0) { list_destroy(hops); return -1; } } } return 0; }

3、拓撲排序-深度優先搜尋
某些階段必須在其他階段之前完成,採用優先順序圖建模。在優先順序圖中,頂點代表任務,邊代表任務之間的依賴關係。
這裡寫圖片描述
遞迴到最深處的點,塗黑、壓棧
(1)資料結構

typedef struct DfsVertex_{
    void *data;
    VertexColor color;
}DfsVertex;

(2)遞迴深度搜索

//ordered:存放由最深處點開始的鏈路
int dfs_main(Graph *graph, AdjList *adjlist, List *ordered)
{
    AdjList  *clr_adjlist;
    BfsVertex *clr_vertex, *adj_vertex;
    LIST_ELEMENT  *member;
    ((DfsVertex *)adjlist->vertex)->color = gray;

    //遍歷當前節點的鄰節點 
    for(member = list_head(&adjlist->adjacent); member != NULL; member = list_next(member))
    {
        adj_vertex = list_data(member);
        if(graph_adjlist(graph, adj_vertex, &clr_adjlist) != 0)
            return -1;
        clr_vertex = clr_adjlist->vertex;

        //往深處遞迴 
        if(clr_vertex->color == white)
        {
            if(dfs_main(graph, clr_adjlist, ordered) != 0)
                return -1;
        }
    }

    //第一個塗黑並壓棧的其實是最深處的點 
    ((DfsVertex *)adjlist->vertex)->color = black;
    if(list_ins_next(ordered, NULL, (DfsVertex *)adjlist->vertex) != 0)
        return -1;
    return 0; 
} 

(3)初始化,對每個白點執行深度搜索

int dfs(Graph *graph, List *ordered)
{
    DfsVertex *vertex;
    LIST_ELEMENT *elememt;
    for(elememt = list_head(graph->adjlists); elememt != NULL; elememt = list_next(elememt))
    {
        vertex = ((AdjList *)list_data(elememt))->vertex;
        vertex->color = white;
    }
    list_init(ordered, NULL);

    for(elememt = list_head(graph->adjlists); elememt != NULL; elememt = list_next(elememt))
    {
        vertex = ((AdjList *)list_data(elememt))->vertex;
        if(vertex->color == white)
        {
            if(dfs_main(graph, (AdjList *)list_data(elememt), ordered) != 0)
            {
                list_destroy(ordered);
                return -1;
            }
        }
    }
    return 0;
}