数据结构笔记-----图
图的定义
都是图,可以用来描述生活里的各种情况
社交网络应用
小结
图的存储结构
邻接矩阵法
代码:
<strong><span style="font-size:18px;">#ifndef _MGRAPH_H_ #define _MGRAPH_H_ typedef void MGraph; typedef void MVertex; typedef void (MGraph_Printf)(MVertex*); MGraph* MGraph_Create(MVertex** v, int n); void MGraph_Destroy(MGraph* graph); void MGraph_Clear(MGraph* graph); int MGraph_AddEdge(MGraph* graph, int v1, int v2, int w); int MGraph_RemoveEdge(MGraph* graph, int v1, int v2); int MGraph_GetEdge(MGraph* graph, int v1, int v2); int MGraph_TD(MGraph* graph, int v); int MGraph_VertexCount(MGraph* graph); int MGraph_EdgeCount(MGraph* graph); void MGraph_DFS(MGraph* graph, int v, MGraph_Printf* pFunc); void MGraph_BFS(MGraph* graph, int v, MGraph_Printf* pFunc); void MGraph_Display(MGraph* graph, MGraph_Printf* pFunc); #endif</span></strong>
<strong><span style="font-size:18px;">#include <malloc.h> #include <stdio.h> #include "MGraph.h" #include "LinkQueue.h" typedef struct _tag_MGraph { int count; MVertex** v; int** matrix; } TMGraph; static void recursive_dfs(TMGraph* graph, int v, int visited[], MGraph_Printf* pFunc) { int i = 0; pFunc(graph->v[v]); visited[v] = 1; printf(", "); for(i=0; i<graph->count; i++) { if( (graph->matrix[v][i] != 0) && !visited[i] ) { recursive_dfs(graph, i, visited, pFunc); } } } static void bfs(TMGraph* graph, int v, int visited[], MGraph_Printf* pFunc) { LinkQueue* queue = LinkQueue_Create(); if( queue != NULL ) { LinkQueue_Append(queue, graph->v + v); //不可以在队列中加入值为0的元素 visited[v] = 1; while( LinkQueue_Length(queue) > 0 ) { int i = 0; v = (MVertex**)LinkQueue_Retrieve(queue) - graph->v; pFunc(graph->v[v]); printf(", "); for(i=0; i<graph->count; i++) { if( (graph->matrix[v][i] != 0) && !visited[i] ) { LinkQueue_Append(queue, graph->v + i); visited[i] = 1; } } } } LinkQueue_Destroy(queue); } MGraph* MGraph_Create(MVertex** v, int n) // O(n) { TMGraph* ret = NULL; if( (v != NULL ) && (n > 0) ) { ret = (TMGraph*)malloc(sizeof(TMGraph)); if( ret != NULL ) { int* p = NULL; ret->count = n; ret->v = (MVertex**)malloc(sizeof(MVertex*) * n); //结点 ret->matrix = (int**)malloc(sizeof(int*) * n); //通过二级指针动态申请一维指针数组 p = (int*)calloc(n * n, sizeof(int)); //通过一级指针申请数据空间 if( (ret->v != NULL) && (ret->matrix != NULL) && (p != NULL) ) { int i = 0; for(i=0; i<n; i++) { ret->v[i] = v[i]; ret->matrix[i] = p + i * n; //将一维指针数组中的指针连接到数据空间 } } else {//异常处理 free(p); free(ret->matrix); free(ret->v); free(ret); ret = NULL; } } } return ret; } void MGraph_Destroy(MGraph* graph) // O(1) { TMGraph* tGraph = (TMGraph*)graph; if( tGraph != NULL ) { free(tGraph->v); free(tGraph->matrix[0]); //释放首地址 free(tGraph->matrix); //释放一维数组 free(tGraph); //这几步不能乱 } } void MGraph_Clear(MGraph* graph) // O(n*n) { TMGraph* tGraph = (TMGraph*)graph; if( tGraph != NULL ) { int i = 0; int j = 0; for(i=0; i<tGraph->count; i++) { for(j=0; j<tGraph->count; j++) { tGraph->matrix[i][j] = 0; } } } } int MGraph_AddEdge(MGraph* graph, int v1, int v2, int w) // O(1) { TMGraph* tGraph = (TMGraph*)graph; int ret = (tGraph != NULL); ret = ret && (0 <= v1) && (v1 < tGraph->count); ret = ret && (0 <= v2) && (v2 < tGraph->count); ret = ret && (0 <= w); if( ret ) { tGraph->matrix[v1][v2] = w; } return ret; } int MGraph_RemoveEdge(MGraph* graph, int v1, int v2) // O(1) { int ret = MGraph_GetEdge(graph, v1, v2); if( ret != 0 ) { ((TMGraph*)graph)->matrix[v1][v2] = 0; } return ret; } int MGraph_GetEdge(MGraph* graph, int v1, int v2) // O(1) { TMGraph* tGraph = (TMGraph*)graph; int condition = (tGraph != NULL); int ret = 0; condition = condition && (0 <= v1) && (v1 < tGraph->count); condition = condition && (0 <= v2) && (v2 < tGraph->count); if( condition ) { ret = tGraph->matrix[v1][v2]; } return ret; } int MGraph_TD(MGraph* graph, int v) // O(n) 度 { TMGraph* tGraph = (TMGraph*)graph; int condition = (tGraph != NULL); int ret = 0; condition = condition && (0 <= v) && (v < tGraph->count); if( condition ) { int i = 0; for(i=0; i<tGraph->count; i++) { if( tGraph->matrix[v][i] != 0 ) { ret++; } if( tGraph->matrix[i][v] != 0 ) { ret++; } } } return ret; } int MGraph_VertexCount(MGraph* graph) // O(1) { TMGraph* tGraph = (TMGraph*)graph; int ret = 0; if( tGraph != NULL ) { ret = tGraph->count; } return ret; } int MGraph_EdgeCount(MGraph* graph) // O(n*n) { TMGraph* tGraph = (TMGraph*)graph; int ret = 0; if( tGraph != NULL ) { int i = 0; int j = 0; for(i=0; i<tGraph->count; i++) { for(j=0; j<tGraph->count; j++) { if( tGraph->matrix[i][j] != 0 ) { ret++; } } } } return ret; } void MGraph_DFS(MGraph* graph, int v, MGraph_Printf* pFunc) {//深度优先遍历 TMGraph* tGraph = (TMGraph*)graph; int* visited = NULL; int condition = (tGraph != NULL); condition = condition && (0 <= v) && (v < tGraph->count); condition = condition && (pFunc != NULL); condition = condition && ((visited = (int*)calloc(tGraph->count, sizeof(int))) != NULL); if( condition ) { int i = 0; recursive_dfs(tGraph, v, visited, pFunc); for(i=0; i<tGraph->count; i++) { if( !visited[i] ) { recursive_dfs(tGraph, i, visited, pFunc); } } printf("\n"); } free(visited); }</span></strong>
<strong><span style="font-size:18px;">void MGraph_BFS(MGraph* graph, int v, MGraph_Printf* pFunc) {//广度优先遍历 TMGraph* tGraph = (TMGraph*)graph; int* visited = NULL; int condition = (tGraph != NULL); condition = condition && (0 <= v) && (v < tGraph->count); condition = condition && (pFunc != NULL); condition = condition && ((visited = (int*)calloc(tGraph->count, sizeof(int))) != NULL); if( condition ) { int i = 0; bfs(tGraph, v, visited, pFunc); for(i=0; i<tGraph->count; i++) { if( !visited[i] ) { bfs(tGraph, i, visited, pFunc); } } printf("\n"); } free(visited); } void MGraph_Display(MGraph* graph, MGraph_Printf* pFunc) // O(n*n) { //MGraph_Display(graph, print_data); TMGraph* tGraph = (TMGraph*)graph; if( (tGraph != NULL) && (pFunc != NULL) ) { int i = 0; int j = 0; for(i=0; i<tGraph->count; i++) { printf("%d:", i); pFunc(tGraph->v[i]); printf(" "); } printf("\n"); for(i=0; i<tGraph->count; i++) { for(j=0; j<tGraph->count; j++) { if( tGraph->matrix[i][j] != 0 ) { printf("<"); pFunc(tGraph->v[i]); //print_data printf(", "); pFunc(tGraph->v[j]); printf(", %d", tGraph->matrix[i][j]); printf(">"); printf(" "); } } } printf("\n"); } } </span></strong>
<strong><span style="font-size:18px;">#include <stdio.h> #include <stdlib.h> #include "MGraph.h" /* run this program using the console pauser or add your own getch, system("pause") or input loop */ void print_data(MVertex* v) { printf("%s", (char*)v); } int main(int argc, char *argv[]) { MVertex* v[] = {"A", "B", "C", "D", "E", "F"}; MGraph* graph = MGraph_Create(v, 6); MGraph_AddEdge(graph, 0, 1, 1); MGraph_AddEdge(graph, 0, 2, 1); MGraph_AddEdge(graph, 0, 3, 1); MGraph_AddEdge(graph, 1, 5, 1); MGraph_AddEdge(graph, 1, 4, 1); MGraph_AddEdge(graph, 2, 1, 1); MGraph_AddEdge(graph, 3, 4, 1); MGraph_AddEdge(graph, 4, 2, 1); MGraph_Display(graph, print_data); MGraph_DFS(graph, 0, print_data); MGraph_BFS(graph, 0, print_data); MGraph_Destroy(graph); return 0; }</span></strong>
图的遍历
深度优先遍历
广度优先遍历
代码
<strong><span style="font-size:18px;">#include <malloc.h> #include <stdio.h> #include "LGraph.h" #include "LinkList.h" #include "LinkQueue.h" typedef struct _tag_LGraph { int count; LVertex** v; LinkList** la; } TLGraph; typedef struct _tag_ListNode { LinkListNode header; int v; int w; } TListNode; static void recursive_dfs(TLGraph* graph, int v, int visited[], LGraph_Printf* pFunc) { int i = 0; pFunc(graph->v[v]); visited[v] = 1; printf(", "); for(i=0; i<LinkList_Length(graph->la[v]); i++) { TListNode* node = (TListNode*)LinkList_Get(graph->la[v], i); if( !visited[node->v] ) { recursive_dfs(graph, node->v, visited, pFunc); } } } static void bfs(TLGraph* graph, int v, int visited[], LGraph_Printf* pFunc) { LinkQueue* queue = LinkQueue_Create(); if( queue != NULL ) { LinkQueue_Append(queue, graph->v + v); visited[v] = 1; while( LinkQueue_Length(queue) > 0 ) { int i = 0; v = (LVertex**)LinkQueue_Retrieve(queue) - graph->v; pFunc(graph->v[v]); printf(", "); for(i=0; i<LinkList_Length(graph->la[v]); i++) { TListNode* node = (TListNode*)LinkList_Get(graph->la[v], i); if( !visited[node->v] ) { LinkQueue_Append(queue, graph->v + node->v); visited[node->v] = 1; } } } } LinkQueue_Destroy(queue); } LGraph* LGraph_Create(LVertex** v, int n) // O(n) { TLGraph* ret = NULL; int ok = 1; if( (v != NULL ) && (n > 0) ) { ret = (TLGraph*)malloc(sizeof(TLGraph)); if( ret != NULL ) { ret->count = n; ret->v = (LVertex**)calloc(n, sizeof(LVertex*)); ret->la = (LinkList**)calloc(n, sizeof(LinkList*)); ok = (ret->v != NULL) && (ret->la != NULL); if( ok ) { int i = 0; for(i=0; i<n; i++) { ret->v[i] = v[i]; } for(i=0; (i<n) && ok; i++) { ok = ok && ((ret->la[i] = LinkList_Create()) != NULL); } } if( !ok ) { if( ret->la != NULL ) { int i = 0; for(i=0; i<n; i++) { LinkList_Destroy(ret->la[i]); } } free(ret->la); free(ret->v); free(ret); ret = NULL; } } } return ret; } void LGraph_Destroy(LGraph* graph) // O(n*n) { TLGraph* tGraph = (TLGraph*)graph; LGraph_Clear(tGraph); if( tGraph != NULL ) { int i = 0; for(i=0; i<tGraph->count; i++) { LinkList_Destroy(tGraph->la[i]); } free(tGraph->la); free(tGraph->v); free(tGraph); } } void LGraph_Clear(LGraph* graph) // O(n*n) { TLGraph* tGraph = (TLGraph*)graph; if( tGraph != NULL ) { int i = 0; for(i=0; i<tGraph->count; i++) { while( LinkList_Length(tGraph->la[i]) > 0 ) { free(LinkList_Delete(tGraph->la[i], 0)); } } } } int LGraph_AddEdge(LGraph* graph, int v1, int v2, int w) // O(1) { TLGraph* tGraph = (TLGraph*)graph; TListNode* node = NULL; int ret = (tGraph != NULL); ret = ret && (0 <= v1) && (v1 < tGraph->count); ret = ret && (0 <= v2) && (v2 < tGraph->count); ret = ret && (0 < w) && ((node = (TListNode*)malloc(sizeof(TListNode))) != NULL); if( ret ) { node->v = v2; node->w = w; LinkList_Insert(tGraph->la[v1], (LinkListNode*)node, 0); } return ret; } int LGraph_RemoveEdge(LGraph* graph, int v1, int v2) // O(n*n) { TLGraph* tGraph = (TLGraph*)graph; int condition = (tGraph != NULL); int ret = 0; condition = condition && (0 <= v1) && (v1 < tGraph->count); condition = condition && (0 <= v2) && (v2 < tGraph->count); if( condition ) { TListNode* node = NULL; int i = 0; for(i=0; i<LinkList_Length(tGraph->la[v1]); i++) { node = (TListNode*)LinkList_Get(tGraph->la[v1], i); if( node->v == v2) { ret = node->w; LinkList_Delete(tGraph->la[v1], i); free(node); break; } } } return ret; } int LGraph_GetEdge(LGraph* graph, int v1, int v2) // O(n*n) { TLGraph* tGraph = (TLGraph*)graph; int condition = (tGraph != NULL); int ret = 0; condition = condition && (0 <= v1) && (v1 < tGraph->count); condition = condition && (0 <= v2) && (v2 < tGraph->count); if( condition ) { TListNode* node = NULL; int i = 0; for(i=0; i<LinkList_Length(tGraph->la[v1]); i++) { node = (TListNode*)LinkList_Get(tGraph->la[v1], i); if( node->v == v2) { ret = node->w; break; } } } return ret; } int LGraph_TD(LGraph* graph, int v) // O(n*n*n) { TLGraph* tGraph = (TLGraph*)graph; int condition = (tGraph != NULL); int ret = 0; condition = condition && (0 <= v) && (v < tGraph->count); if( condition ) { int i = 0; int j = 0; for(i=0; i<tGraph->count; i++) { for(j=0; j<LinkList_Length(tGraph->la[i]); j++) { TListNode* node = (TListNode*)LinkList_Get(tGraph->la[i], j); if( node->v == v ) { ret++; } } } ret += LinkList_Length(tGraph->la[v]); } return ret; } int LGraph_VertexCount(LGraph* graph) // O(1) { TLGraph* tGraph = (TLGraph*)graph; int ret = 0; if( tGraph != NULL ) { ret = tGraph->count; } return ret; } int LGraph_EdgeCount(LGraph* graph) // O(n) { TLGraph* tGraph = (TLGraph*)graph; int ret = 0; if( tGraph != NULL ) { int i = 0; for(i=0; i<tGraph->count; i++) { ret += LinkList_Length(tGraph->la[i]); } } return ret; } void LGraph_DFS(LGraph* graph, int v, LGraph_Printf* pFunc) { TLGraph* tGraph = (TLGraph*)graph; int* visited = NULL; int condition = (tGraph != NULL); condition = condition && (0 <= v) && (v < tGraph->count); condition = condition && (pFunc != NULL); condition = condition && ((visited = (int*)calloc(tGraph->count, sizeof(int))) != NULL); if( condition ) { int i = 0; recursive_dfs(tGraph, v, visited, pFunc); for(i=0; i<tGraph->count; i++) { if( !visited[i] ) { recursive_dfs(tGraph, i, visited, pFunc); } } printf("\n"); } free(visited); } void LGraph_BFS(LGraph* graph, int v, LGraph_Printf* pFunc) {//借助队列实现 TLGraph* tGraph = (TLGraph*)graph; int* visited = NULL; int condition = (tGraph != NULL); condition = condition && (0 <= v) && (v < tGraph->count); condition = condition && (pFunc != NULL); condition = condition && ((visited = (int*)calloc(tGraph->count, sizeof(int))) != NULL); if( condition ) { int i = 0; bfs(tGraph, v, visited, pFunc); for(i=0; i<tGraph->count; i++) { if( !visited[i] ) { bfs(tGraph, i, visited, pFunc); } } printf("\n"); } free(visited); } void LGraph_Display(LGraph* graph, LGraph_Printf* pFunc) // O(n*n*n) { TLGraph* tGraph = (TLGraph*)graph; if( (tGraph != NULL) && (pFunc != NULL) ) { int i = 0; int j = 0; for(i=0; i<tGraph->count; i++) { printf("%d:", i); pFunc(tGraph->v[i]); printf(" "); } printf("\n"); for(i=0; i<tGraph->count; i++) { for(j=0; j<LinkList_Length(tGraph->la[i]); j++) { TListNode* node = (TListNode*)LinkList_Get(tGraph->la[i], j); printf("<"); pFunc(tGraph->v[i]); printf(", "); pFunc(tGraph->v[node->v]); printf(", %d", node->w); printf(">"); printf(" "); } } printf("\n"); } } </span></strong>
<strong><span style="font-size:18px;">#ifndef _LGRAPH_H_ #define _LGRAPH_H_ typedef void LGraph; typedef void LVertex; typedef void (LGraph_Printf)(LVertex*); LGraph* LGraph_Create(LVertex** v, int n); void LGraph_Destroy(LGraph* graph); void LGraph_Clear(LGraph* graph); int LGraph_AddEdge(LGraph* graph, int v1, int v2, int w); int LGraph_RemoveEdge(LGraph* graph, int v1, int v2); int LGraph_GetEdge(LGraph* graph, int v1, int v2); int LGraph_TD(LGraph* graph, int v); int LGraph_VertexCount(LGraph* graph); int LGraph_EdgeCount(LGraph* graph); void LGraph_DFS(LGraph* graph, int v, LGraph_Printf* pFunc); void LGraph_BFS(LGraph* graph, int v, LGraph_Printf* pFunc); void LGraph_Display(LGraph* graph, LGraph_Printf* pFunc); #endif</span></strong>
<strong><span style="font-size:18px;">#include <stdio.h> #include <stdlib.h> #include "LGraph.h" /* run this program using the console pauser or add your own getch, system("pause") or input loop */ void print_data(LVertex* v) { printf("%s", (char*)v); } int main(int argc, char *argv[]) { LVertex* v[] = {"A", "B", "C", "D", "E", "F"}; LGraph* graph = LGraph_Create(v, 6); LGraph_AddEdge(graph, 0, 1, 1); LGraph_AddEdge(graph, 0, 2, 1); LGraph_AddEdge(graph, 0, 3, 1); LGraph_AddEdge(graph, 1, 5, 1); LGraph_AddEdge(graph, 1, 4, 1); LGraph_AddEdge(graph, 2, 1, 1); LGraph_AddEdge(graph, 3, 4, 1); LGraph_AddEdge(graph, 4, 2, 1); LGraph_Display(graph, print_data); LGraph_DFS(graph, 0, print_data); LGraph_BFS(graph, 0, print_data); LGraph_Destroy(graph); return 0; }</span></strong>
邻接矩阵法实现在上面图的存储结构代码
小结
广度优先遍历与深度优先遍历是图结构的基础算法,也是其他图算法的基础。
思考:
借助栈数据结构
最小连通网
运营商的挑战
备选方案
Prim算法
代码
Prim.c
<strong><span style="font-size:18px;">#include <stdio.h> #include <stdlib.h> /* run this program using the console pauser or add your own getch, system("pause") or input loop */ #define VNUM 9 #define MV 65536 int P[VNUM];//结点 int Cost[VNUM];//边的耗费 int Mark[VNUM]; int Matrix[VNUM][VNUM] = { {0, 10, MV, MV, MV, 11, MV, MV, MV}, {10, 0, 18, MV, MV, MV, 16, MV, 12}, {MV, 18, 0, 22, MV, MV, MV, MV, 8}, {MV, MV, 22, 0, 20, MV, MV, 16, 21}, {MV, MV, MV, 20, 0, 26, MV, 7, MV}, {11, MV, MV, MV, 26, 0, 17, MV, MV}, {MV, 16, MV, MV, MV, 17, 0, 19, MV}, {MV, MV, MV, 16, 7, MV, 19, 0, MV}, {MV, 12, 8, 21, MV, MV, MV, MV, 0}, }; void Prim(int sv) // O(n*n) { int i = 0; int j = 0; if( (0 <= sv) && (sv < VNUM) ) { for(i=0; i<VNUM; i++) { Cost[i] = Matrix[sv][i]; P[i] = sv; Mark[i] = 0; } Mark[sv] = 1; for(i=0; i<VNUM; i++) { int min = MV; int index = -1; for(j=0; j<VNUM; j++) { if( !Mark[j] && (Cost[j] < min) ) { min = Cost[j]; index = j; } } if( index > -1 ) { Mark[index] = 1; printf("(%d, %d, %d)\n", P[index], index, Cost[index]); } for(j=0; j<VNUM; j++) {//以index为结点查找最小权值 if( !Mark[j] && (Matrix[index][j] < Cost[j]) ) { Cost[j] = Matrix[index][j]; P[j] = index; } } } } } int main(int argc, char *argv[]) { Prim(0); return 0; }</span></strong>
Kruskal算法
小结
最短路径
解决步骤描述
算法精髓
代码 类似Prim
Dijkstra.c
<strong><span style="font-size:18px;">#include <stdio.h> #include <stdlib.h> /* run this program using the console pauser or add your own getch, system("pause") or input loop */ #define VNUM 5 #define MV 65536 int P[VNUM]; int Dist[VNUM]; int Mark[VNUM]; int Matrix[VNUM][VNUM] = { {0, 10, MV, 30, 100}, {MV, 0, 50, MV, MV}, {MV, MV, 0, MV, 10}, {MV, MV, 20, 0, 60}, {MV, MV, MV, MV, 0}, }; void Dijkstra(int sv) // O(n*n) { int i = 0; int j = 0; if( (0 <= sv) && (sv < VNUM) ) { for(i=0; i<VNUM; i++) { Dist[i] = Matrix[sv][i]; P[i] = sv; Mark[i] = 0; } Mark[sv] = 1; for(i=0; i<VNUM; i++) { int min = MV; int index = -1; for(j=0; j<VNUM; j++) { if( !Mark[j] && (Dist[j] < min) ) { min = Dist[j]; index = j; } } if( index > -1 ) { Mark[index] = 1; } for(j=0; j<VNUM; j++) { if( !Mark[j] && (min + Matrix[index][j] < Dist[j]) ) { Dist[j] = min + Matrix[index][j]; P[j] = index; } } } for(i=0; i<VNUM; i++) { int p = i; printf("%d -> %d: %d\n", sv, p, Dist[p]); do { printf("%d <- ", p); p = P[p]; } while( p != sv ); printf("%d\n", p); } } } int main(int argc, char *argv[]) { Dijkstra(0); return 0; } </span></strong>
A矩阵的意义
代码
Floyd.c
#include <stdio.h> #include <stdlib.h> /* run this program using the console pauser or add your own getch, system("pause") or input loop */ #define VNUM 5 #define MV 65536 int P[VNUM][VNUM]; int A[VNUM][VNUM]; int Matrix[VNUM][VNUM] = { {0, 10, MV, 30, 100}, {MV, 0, 50, MV, MV}, {MV, MV, 0, MV, 10}, {MV, MV, 20, 0, 60}, {MV, MV, MV, MV, 0}, }; void Floyd() // O(n*n*n) { int i = 0; int j = 0; int k = 0; for(i=0; i<VNUM; i++) { for(j=0; j<VNUM; j++) { A[i][j] = Matrix[i][j]; P[i][j] = j; //保存正序的第二个顶点 } } for(i=0; i<VNUM; i++) { for(j=0; j<VNUM; j++) { for(k=0; k<VNUM; k++) { if( (A[j][i] + A[i][k]) < A[j][k] ) { A[j][k] = A[j][i] + A[i][k]; P[j][k] = P[j][i]; //通过中转 } } } } for(i=0; i<VNUM; i++) { for(j=0; j<VNUM; j++) { int p = -1; printf("%d -> %d: %d\n", i, j, A[i][j]); printf("%d", i); p = i; do { p = P[p][j]; printf(" -> %d", p); } while( p != j); printf("\n"); } } } int main(int argc, char *argv[]) { Floyd(); return 0; }
小结
思考: