一个图 G = (V,E)由顶点(vertex)集 V 和边(edge)集 E 组成。每一条边就是一个点对(v,w),其中 v,w ∈V。
图的表示
图的存储一般有邻接表和邻接矩阵两种。若图是稠密的,则宜采用邻接矩阵;图是稀疏的,则应改用邻接表。这里我们先讨论图的邻接表存储方式。
先看下面的无向图(图片来源于网络)
邻接表形式
上面的边没有赋予权重,考虑边的权重,可以在邻接表后面的链表节点中添加 weight 变量表示。
邻接表前面的数组表示各个顶点,后面的链表节点分别表示与该顶点相连接的顶点。边则由两个顶点组成(最前面的顶点分别与后面对应的链表节点的顶点组合而成)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
| 图的数据结构
typedef struct _AdjListNode { int end; int weight; struct _AdjListNode *next; }AdjListNode;
typedef struct _AdjList { AdjListNode *head; }AdjList;
typedef struct _Graph { int vertices; int edges; AdjList *array; }Graph; 图的创建
Graph* CreateGraph(int V) { Graph *graph = new Graph; assert(graph); graph->vertices = V; graph->edges = 0;
graph->array = new AdjList[V]; for (int i = 0; i < V; ++i) { graph->array[i].head = NULL; } return graph;
} 添加边
void AddEdge(Graph *graph, int begin, int end, int weight) { AdjListNode *newNode = new AdjListNode; assert(newNode); newNode->end = end; newNode->weight = weight; newNode->next = graph->array[begin].head; graph->array[begin].head = newNode;
newNode = new AdjListNode; newNode->end = begin; newNode->weight = weight; newNode->next = graph->array[end].head; graph->array[end].head = newNode; graph->edges++;
} 销毁图
void GraphDestory(Graph *graph) { AdjListNode *delNode = NULL; for (int i = 0; i < graph->vertices; ++i) { delNode = graph->array[i].head; while (delNode) { AdjListNode *temp = delNode; delNode = delNode->next; delete temp; } graph->array[i].head = NULL; } delete[] graph->array; delete graph; } 返回图的顶点数和边数
int GraphVerticesNum(Graph *graph) { return graph->vertices; }
int GraphEdgesNum(Graph *graph) { return graph->edges; } 检查两个顶点之间是否有边
bool GraphHasEdge(Graph *graph, int begin, int end) { assert(begin != end);
AdjListNode *node = graph->array[begin].head; while (node) { if (end == node->end) return true; node = node->next; } return false;
} 图就是多个链表的聚合。
理解了图的邻接表存储,后面的代码就好实现了。 基于前面的分析上,下面给出借助STL中的list 来构建邻接表的图,前面需要自己构建链表,最终实现的图结构是一样的,但是代码的简洁度不是差了一点半点:
class graph { public: graph(int v) :vertex(v){ adj = new list<int>[v]; }
void addEdge(int v, int w);
private: int vertex; list<int> *adj; };
void graph::addEdge(int v, int w) { adj[v].push_back(w); } 构建时,只需要对照邻接表来添加边。 下面上面创建一个图过于繁琐,这里更新一下,一举根据输入创建一个图,2015.7更新
typedef int VertexType; typedef int EdgeType;
typedef struct AdjNode { int adjvex; int weight; struct AdjNode *next; }AdjNode;
typedef struct VertexNode { VertexType data; AdjNode *pFfirstedge; }VertexNode;
typedef struct Graph { VertexNode *AdjArray; int numVertexes; int numEdges; }Graph;
Graph* CreateGraph() { Graph *pGraph = new Graph; AdjNode *pNode = NULL; if (NULL == pGraph) return NULL;
cout << "输入顶点数和边数:" << endl; cin >> pGraph->numVertexes >> pGraph->numEdges; pGraph->AdjArray = new VertexNode[pGraph->numVertexes](); if (NULL == pGraph->AdjArray) { delete pGraph; return NULL; } for (int i = 0; i < pGraph->numVertexes; ++i) {
(pGraph->AdjArray)[i].data = i; } for (int k = 0; k < pGraph->numEdges; ++k) { int i, j, w; cout << "输入边<vi,vj>上的下标i,下标j和权重w:" << endl; cin >> i >> j >> w; pNode = new AdjNode; if (NULL == pNode) { delete[] pGraph->AdjArray; delete pGraph; return NULL; } pNode->adjvex = j; pNode->weight = w; pNode->next = (pGraph->AdjArray)[i].pFfirstedge; (pGraph->AdjArray)[i].pFfirstedge = pNode; AdjNode *pNode = new AdjNode; if (NULL == pNode) { delete[] pGraph->AdjArray; delete pGraph; return NULL; } pNode->adjvex = i; pNode->weight = w; pNode->next = (pGraph->AdjArray)[j].pFfirstedge; (pGraph->AdjArray)[j].pFfirstedge = pNode; } return pGraph;
}
|
图结构关键在于理解图的存储方式,理解了其存储方式,对于创建图以及遍历就很好理解实现了。