c/c++ 有向無環圖 directed acycline graph
阿新 • • 發佈:2018-08-06
rect 如果 拓撲排序 type 第一個 ima 結構 alt lse
c/c++ 有向無環圖 directed acycline graph
概念:
圖中點與點之間的線是有方向的,圖中不存在環。用鄰接表的方式,實現的圖。
名詞:
- 頂點的入度:到這個頂點的線的數量。
- 頂點的出度:從這個頂點出發的線的數量。
實現思路:
1,計算出每個頂點的入度,存放到輔助數組cnt中
2,找到入度為0的頂點集合。
3,從入度為0的頂點集合,拿出一個頂點,這個頂點就是第一個頂點(不唯一)。
4,找到與以3處頂點為出發點的頂點,然後把這些頂點的入度減一,減一後發現如果入度為0了,更新輔助數組cnt
5,重復2-4
難點:
輔助數組cnt的作用:
- 剛開始是存放每個頂點的入度
- 找到入度為0的頂點後,入棧;出棧的元素就是找到的頂點,發現入度為0的頂點後,繼續入棧,然後出棧...
輔助數組cnt的運用,建議用gdb,多debug幾次,就能明白了。
圖為下圖1:
圖1
graph_link.h
#ifndef __graph_link__ #define __graph_link__ #include <stdio.h> #include <malloc.h> #include <assert.h> #include <memory.h> #define default_vertex_size 10 #define T char //邊的結構 typedef struct Edge{ //頂點的下標 int idx; //指向下一個邊的指針 struct Edge* link; }Edge; //頂點的結構 typedef struct Vertex{ //頂點的值 T data; //邊 Edge* adj; }Vertex; //圖的結構 typedef struct GraphLink{ int MaxVertices; int NumVertices; int NumEdges; Vertex* nodeTable; }GraphLink; //初始化圖 void init_graph_link(GraphLink* g); //顯示圖 void show_graph_link(GraphLink* g); //插入頂點 void insert_vertex(GraphLink* g, T v); //插入邊尾插 void insert_edge_tail(GraphLink* g, T v1, T v2); //插入邊頭插 void insert_edge_head(GraphLink* g, T v1, T v2); //取得指定頂點的第一個後序頂點 int get_first_neighbor(GraphLink* g, T v); //取得指定頂點v1的臨街頂點v2的第一個後序頂點 int get_next_neighbor(GraphLink* g, T v1, T v2); //拓撲排序 void topo_sort(GraphLink* g); #endif
graph_link.c
#include "graph_link.h" //初始化圖 void init_graph_link(GraphLink* g){ g->MaxVertices = default_vertex_size; g->NumVertices = g->NumEdges = 0; g->nodeTable = (Vertex*)malloc(sizeof(Vertex) * g->MaxVertices); assert(NULL != g->nodeTable); for(int i = 0; i < g->MaxVertices; ++i){ g->nodeTable[i].adj = NULL; } } //顯示圖 void show_graph_link(GraphLink* g){ if(NULL == g)return; for(int i = 0; i < g->NumVertices; ++i){ printf("%d %c->", i, g->nodeTable[i].data); Edge* p = g->nodeTable[i].adj; while(NULL != p){ printf("%d->", p->idx); p = p->link; } printf(" NULL\n"); } } //插入頂點 void insert_vertex(GraphLink* g, T v){ if(g->NumVertices >= g->MaxVertices)return; g->nodeTable[g->NumVertices++].data = v; } //查找頂點的index int getVertexIndex(GraphLink* g, T v){ for(int i = 0; i < g->NumVertices; ++i){ if(v == g->nodeTable[i].data)return i; } return -1; } //創建邊 void buyEdge(Edge** e, int idx){ Edge* p = (Edge*)malloc(sizeof(Edge)); p->idx = idx; p->link = NULL; if(NULL == *e){ *e = p; } else{ Edge* tmp = *e; while(tmp->link != NULL){ tmp = tmp->link; } tmp->link = p; } } //插入邊(尾插) void insert_edge_tail(GraphLink* g, T v1, T v2){ int p1 = getVertexIndex(g, v1); int p2 = getVertexIndex(g, v2); if(p1 == -1 || p2 == -1)return; buyEdge(&(g->nodeTable[p1].adj), p2); g->NumEdges++; buyEdge(&(g->nodeTable[p2].adj), p1); g->NumEdges++; } //插入邊(頭插) void insert_edge_head(GraphLink* g, T v1, T v2){ int p1 = getVertexIndex(g, v1); int p2 = getVertexIndex(g, v2); if(p1 == -1 || p2 == -1)return; Edge* p = (Edge*)malloc(sizeof(Edge)); p->idx = p2; p->link = g->nodeTable[p1].adj; g->nodeTable[p1].adj = p; /* p = (Edge*)malloc(sizeof(Edge)); p->idx = p1; p->link = g->nodeTable[p2].adj; g->nodeTable[p2].adj = p; */ } //取得指定頂點的第一個後序頂點 int get_first_neighbor(GraphLink* g, T v){ int i = getVertexIndex(g, v); if (-1 == i)return -1; Edge* p = g->nodeTable[i].adj; if(NULL != p) return p->idx; else return -1; } //取得指定頂點v1的臨街頂點v2的第一個後序頂點 int get_next_neighbor(GraphLink* g, T ve1, T ve2){ int v1 = getVertexIndex(g, ve1); int v2 = getVertexIndex(g, ve2); if(v1 == -1 || v2 == -1)return -1; Edge* t = g->nodeTable[v1].adj; while(t != NULL && t->idx != v2){ t = t->link; } if(NULL != t && t->link != NULL){ return t->link->idx; } return -1; } //拓撲排序 void topo_sort(GraphLink* g){ int n = g->NumVertices; //表示各個頂點的入度,先都初始化為0 int* cnt = (int*)malloc(sizeof(int) * n); assert(NULL != cnt); for(int i = 0; i < n; ++i){ cnt[i] = 0; } Edge* p; //算出各個頂點的入度 for(int i = 0; i < n; ++i){ p = g->nodeTable[i].adj; while(p != NULL){ cnt[p->idx]++; p = p->link; } } int top = -1; for(int i = 0; i < n; ++i){ if(cnt[i] == 0){ //入度為0的頂點入棧(模擬入棧) cnt[i] = top; //push top = i; } } int v,w; for(int i = 0; i < n; ++i){ if(top == -1)return;//有回路存在 v = top; //模擬出棧 top = cnt[top]; printf("%c->", g->nodeTable[v].data); w = get_first_neighbor(g, g->nodeTable[v].data); while(-1 != w){ if(--cnt[w] == 0){ //入度為0的頂點入棧(模擬入棧) cnt[w] = top; top = w; } w = get_next_neighbor(g,g->nodeTable[v].data,g->nodeTable[w].data); } } free(cnt); }
graph_linkmain.c
#include "graph_link.h"
int main(){
GraphLink gl;
//初始化圖
init_graph_link(&gl);
//插入節點
insert_vertex(&gl, ‘A‘);
insert_vertex(&gl, ‘B‘);
insert_vertex(&gl, ‘C‘);
insert_vertex(&gl, ‘D‘);
insert_vertex(&gl, ‘E‘);
insert_vertex(&gl, ‘F‘);
//插入邊(頭插)
insert_edge_head(&gl, ‘A‘, ‘B‘);
insert_edge_head(&gl, ‘A‘, ‘C‘);
insert_edge_head(&gl, ‘A‘, ‘D‘);
insert_edge_head(&gl, ‘C‘, ‘B‘);
insert_edge_head(&gl, ‘C‘, ‘E‘);
insert_edge_head(&gl, ‘D‘, ‘E‘);
insert_edge_head(&gl, ‘F‘, ‘D‘);
insert_edge_head(&gl, ‘F‘, ‘E‘);
//顯示圖
show_graph_link(&gl);
//拓撲排序
topo_sort(&gl);
printf("\n");
}
完整代碼
編譯方法:gcc -g graph_link.c graph_linkmain.c
c/c++ 有向無環圖 directed acycline graph