【WIP_S9】图论算法
创建: 2018/06/01
图的概念 | |
|
有向边 有向图 无向边 无向图 点的次数: 点连接的边的数量 闭路: 起点和重点一样 连接图: 任意两点之间都可到达 无闭路有向图: 没有闭路的有向图 森林: 互素的树的集合 生成树: 含有图里所有点的树 生成树林: 所有生成树的并集 |
图论算法的应用 | |
● 电路的元件关系 ● 交通网 ● 电脑网络(本地网络, 互联网, web等) ● 数据库(实体关系图(ER图)) |
|
图的数据结构 | |
邻接矩阵 |
适用于数据多的 //------------------------------------------------ // 邻接矩阵 //------------------------------------------------ struct Graph { int v; int e; int **adj; }; // 创建图 struct Graph *adjMatrixOfGraph() { int i, u, v; struct Graph *G = (struct Graph *)malloc(sizeof(struct Graph)); if (G == NULL) { printf("memory error\n"); return NULL; } printf("Number of Verticees: "); scanf("%d", &G->v); printf("Number of Edges: "); scanf("%d", &G->e); G->adj = (int **)malloc(sizeof(int *) * G->v); if (G->adj == NULL) { printf("Memory Error\n"); return NULL; } for (i = 0; i < G->v; i++) { G->adj[i] = (int *)malloc(sizeof(int) * G->v); if (G->adj[i] == NULL) { printf("Memory Error\n"); return NULL; } } printf("v: %d, e: %d\n", G->v, G->e); for (u=0; u<G->v; u++) { // 初始化点 for (v=0; v<G->v; v++) { if (u==v) { G->adj[u][v] = 1; } else { G->adj[u][v] = 0; // 以0初始化矩阵 } } } for (i=0; i<G->e; i++) { // 初始化边 printf("Reading Edge: "); scanf("%d %d", &u, &v); G->adj[u][v] = G->adj[v][u] = 1; } return G; }
|
邻接链表 |
适用于数据小的 //------------------------------------------------ // 邻接链表 //------------------------------------------------ struct S9ListNode { int vertexNumber; struct S9ListNode *next; }; struct ListGraph { int v; int e; struct S9ListNode *adj; }; struct ListGraph *adjListOfGraph() { // 无向图 int i, x, y; struct S9ListNode *temp; struct ListGraph *G = (struct ListGraph *)malloc(sizeof(struct ListGraph)); if (G == NULL) { printf("Memory Error\n"); return NULL; } printf("Number of Vertices: "); scanf("%d", &G->v); printf("Number of Edges: "); scanf("%d", &G->e); G->adj = (struct S9ListNode *)malloc(sizeof(struct S9ListNode)*G->v); if (G->adj == NULL) { printf("Memory Error\n"); return NULL; } for (i=0; i<G->v; i++) { // 先初始化所有链表 G->adj[i] = *(struct S9ListNode *)malloc(sizeof(struct S9ListNode)); G->adj[i].vertexNumber = i; G->adj[i].next = &G->adj[i]; } for (i=0; i<G->e; i++) { printf("Reading Edge: "); scanf("%d %d", &x, &y); struct S9ListNode *node; temp = (struct S9ListNode *)malloc(sizeof(struct S9ListNode)); // 把y添加到x的链表上 temp->vertexNumber = y; temp->next = &G->adj[x]; node = &G->adj[x]; while (node != NULL && node->next != &G->adj[x]) { node = node->next; } node->next = temp; // 把x添加到y的链表山 temp = (struct S9ListNode *)malloc(sizeof(struct S9ListNode)); temp->vertexNumber = x; temp->next = &G->adj[y]; node = &G->adj[y]; while (node != NULL && node->next != &G->adj[y]) { node = node->next; } node->next = temp; } return G; }
|
图的遍历 | |
DFS 深度优先搜索 |
Depth First Search //------------------------------------------------ // 深度优先搜索 DFS //------------------------------------------------ int visited[128]; // 实际只需要点的数量的长度 // 状态: 1: 已访问 0: 未访问 // 邻接矩阵的DFS void depthFirstSearch(struct Graph *g, int u) { int v; visited[u] = 1; printf("%d visited\n", u); // 访问中的处理 for (v = 0; v <g->v; v++) { // 对点u连接的未访问的节点进行访问 if (visited[v] == 0 && g->adj[u][v] != 0) { // 节点并未访问且u和v连接 depthFirstSearch(g, v); // 从v出发 } } } void depthFirstSearchTraversal(struct Graph *g) { int i; for (i = 0; i < g->v; i++) { // 初始化访问表 visited[i] = 0; } // 有不通的子连接图时需要 for (i = 0; i < g->v; i++) { if (visited[i] == 0) { depthFirstSearch(g, i); // 一次呼出直接遍历完i可到的所有点 } } } // 邻接链表的DFS void depthFirstSearch_List(struct ListGraph *g, int u) { struct S9ListNode *temp = g->adj[u].next; visited[u] = 1; printf("%d visited\n", u); // 访问中的处理 while (temp != &g->adj[u]) { if (visited[temp->vertexNumber] == 0) { depthFirstSearch_List(g, temp->vertexNumber); } temp = temp->next; } } void depthFirstSearchTraversal_List(struct ListGraph *g) { int i; for (i = 0; i < g->v; i++) { // 初始化访问表 visited[i] = 0; } // 有不通的子连接图时需要 for (i = 0; i < g->v; i++) { if (visited[i] == 0) { depthFirstSearch_List(g, i); // 一次呼出直接遍历完i可到的所有点 } } }
|
BFS 宽度优先搜索 |
Breadth First Search
//------------------------------------------------ // 宽度优先搜索 BFS //------------------------------------------------ struct S9QueueNode { int data; struct S9QueueNode *next; }; struct S9Queue { struct S9QueueNode *front; }; struct S9Queue *S9CreateQueue() { struct S9Queue *q = (struct S9Queue *)malloc(sizeof(struct S9Queue)); if (q == NULL) { return NULL; } q->front = NULL; return q; } int S9DeQueue(struct S9Queue *queue) { if (queue==NULL) { return -1; } if (queue->front == NULL) { return -1; } struct S9QueueNode *temp = queue->front; if (queue->front == NULL) { return -1; } int data = temp->data; queue->front = queue->front->next; free(temp); return data; } void S9EnQueue(struct S9Queue *queue, int data) { if (queue == NULL) { queue = (struct S9Queue *)malloc(sizeof(struct S9Queue)); } struct S9QueueNode *newNode = (struct S9QueueNode *)malloc(sizeof(struct S9QueueNode)); struct S9QueueNode *temp = queue->front; newNode->next = NULL; newNode->data = data; if (temp == NULL) { queue->front = newNode; } else { while (temp->next != NULL) { temp = temp->next; } temp->next = newNode; } } void S9FreeQueue(struct S9Queue *q) { if (q == NULL) { return; } if (q->front != NULL) { struct S9QueueNode *temp = q->front, *temp2; while (temp != NULL) { temp2 = temp; temp = temp->next; free(temp2); } } free(q); } int S9IsEmptyQueue(struct S9Queue *queue) { // true: 1, false: 0 if (queue == NULL) { return 1; } int result = queue->front == NULL ? 1 : 0; return result; } void S9ShowQueue(struct S9Queue *q) { if (q == NULL) { printf("queue is null\n"); return; } if (q->front == NULL) { printf("queue has no data\n"); return; } struct S9QueueNode *temp = q->front; int count = 0; while (temp) { printf("[%d]: %d ", count, temp->data); temp = temp->next; count++; } puts(""); } int visited_bfs[128]; void breadthFirstSearch(struct Graph *g, int u) { // 矩阵 int count = 0, i; struct S9Queue *queue = S9CreateQueue(); S9EnQueue(queue, u); while (!S9IsEmptyQueue(queue)) { int u = S9DeQueue(queue); printf("顶点[%d]: %d\n", count, u); count++; visited_bfs[u] = 1; for (i=0; i<g->v; i++) { if (g->adj[u][i] == 1 && visited_bfs[i] == 0) { S9EnQueue(queue, i); } } } S9FreeQueue(queue); } void breadthFirstSearchTravsal(struct Graph *g) { for (int i=0; i<128; i++) { visited_bfs[i] = 0; } for (int i = 0; i<g->v; i++) { if (visited_bfs[i] == 0) { breadthFirstSearch(g, i); } } }
|
最短路径算法 | |
种类 |
● 不带加权的图 ● 带加权的图 ● 有负加权的图 |
应用 |
● 两地间最近的路 ● 从A到B发送数据最便宜的方法 |
不加权的图最短路径 |
//------------------------------------------------ // 不带加权的图 //------------------------------------------------ int distant[128]; int path[128]; void unweightedShortestPath(struct Graph *g, int s) { // 邻接矩阵版 struct S9Queue *queue = S9CreateQueue(); int v, w; S9EnQueue(queue, s); for (int i = 0; i<g->v; i++) { distant[i] = -1; path[i] = -1; // 起点为-1 } distant[s] = 0; while(!S9IsEmptyQueue(queue)) { v = S9DeQueue(queue); for (w = 0; w<g->v; w++) { if (g->adj[v][w] != 0 && distant[w] == -1) { S9EnQueue(queue, w); distant[w] = distant[v] + 1; path[w] = v; } } } S9FreeQueue(queue); }
|
迪杰斯特拉算法 加权图最短路径算法 |
//------------------------------------------------ // 不带负加权的图 迪杰斯特拉算法 //------------------------------------------------ void dijkstra(struct Graph *g, int s) { struct S9Queue *queue = S9CreateQueue(); // 优先队列 int v, w; S9EnQueue(queue, s); for (int i = 0 ; i<g->v; i++) { distant[i] = -1; // -1 表示还没处理 } distant[s] = 0; // 自己到自己的距离为0 while (!S9IsEmptyQueue(queue)) { // v = S9DeQueue(queue); // TODO-PRO: fix here [这里要改成以距离为排序的DeleteMin] v = S9DeleteMin(queue); for (w = 0; w<g->v; w++) { if (g->adj[v][w] != 0) { // v -> w 直接相同 int newDistant = distant[v] + g->adj[v][w]; // 新距离 printf("distant[v]: %d\n", distant[v]); if (distant[w] == -1) { distant[w] = newDistant; S9EnQueue(queue, w); path[w] = v; } else if (newDistant < distant[w]) { distant[w] = newDistant; path[w] = v; // 更新w S9EnQueue(queue, w); } } } } }
|
贝尔曼-福特算法 | 可以有负加权边 |