- 论坛徽章:
- 3
|
本帖最后由 captivated 于 2013-01-27 15:50 编辑
要表示图,需要表示顶点和边。要么用矩阵,要么用邻接表,要么直接用内核链表那种节点做十字交叉链。
LZ用表示树的想法来表示图,感觉怪怪。。。
两个表示图的数据结构示例,首先是矩阵表示法。。。- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define VERTEX_NUM 8
- // 矩阵记录每个顶点的连通状况.
- // edge_cnt记录有多少条边.
- typedef struct _graph graph_t;
- struct _graph {
- int edge[VERTEX_NUM][VERTEX_NUM]; // 边
- int edge_cnt; // 边计数
- int visited[VERTEX_NUM]; // 顶点访问信息
- };
- // 创建图.
- graph_t *graph_create(void)
- {
- graph_t *thiz = malloc(sizeof(graph_t));
- if (NULL == thiz)
- return NULL;
- int i, j;
- for (i = 0; i < VERTEX_NUM; i++)
- for (j = 0; j < VERTEX_NUM; j++)
- {
- thiz->edge[i][j] = 0;
- }
- thiz->edge_cnt = 0;
- return thiz;
- }
- // 增加一条边, 也即将矩阵中沿反对角线对称的两个点位置1.
- // 这个图是无向的.
- void graph_add_edge(graph_t *thiz, int from, int to)
- {
- thiz->edge[from][to] = 1;
- thiz->edge[to][from] = 1;
- thiz->edge_cnt++;
- }
- // 深度优先(depth first search/traverse)搜索/遍历
- void __graph_dfs(graph_t *thiz, int start)
- {
- // 访问的动作就是将该顶点值(其索引)打印.
- printf("%d ", start);
- // 已访问顶点要置位标记
- thiz->visited[start] = 1;
- // edge[start][i]为1则表示边存在(可访问)
- int i;
- for (i = 0; i < VERTEX_NUM; i++)
- {
- if (thiz->edge[start][i] == 1 && thiz->visited[i] == 0)
- __graph_dfs(thiz, i);
- }
- }
- // dfs的外覆器
- void graph_dfs(graph_t *thiz, int start)
- {
- memset(thiz->visited, 0, sizeof(int) * VERTEX_NUM);
- printf("start => ");
- __graph_dfs(thiz, start);
- printf("end.\n");
- }
复制代码 用邻接表表示的:- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define MAX 0xffffff
- // edge infomation, 比如, 用一条边表示两顶点之间的交通状况,
- // 则速度, 交通运输类型, 两顶点之间的距离, 票价如何,etc...
- typedef struct _einfo einfo_t;
- struct _einfo {
- int speed;
- char traffic_style[32];
- int distance;
- int price_per_km;
- };
- // edge,表示一条边
- // w: weight, 权值, 该权值如何可以根据einfo来计算
- // adj: adjacent / adjacency 邻接信息, 与什么顶点相连 -- 对应于vertex中的顶点标记.
- // next: 链表不用说了
- typedef struct _edge edge_t;
- struct _edge {
- einfo_t einfo;
- int w;
- int adj;
- edge_t *next;
- };
- // vertex infomation
- // data: 顶点的标记,标示该顶点,也就是顶点的id, 就像矩阵中用数组索引下标标示顶点一样,
- // 只不过这种结构更灵活一些, id是可选的一个int数值.
- typedef struct _vinfo vinfo_t;
- struct _vinfo {
- char name[32];
- int data;
- };
- // vertex.
- // nei_cnt: how many neighours this vertex hold.
- // visited: has it been visited?
- // head: head pointer of edge list.
- // next: next vertex
- typedef struct _vertex vertex_t;
- struct _vertex {
- vinfo_t vinfo;
- int nei_cnt;
- int visited;
- edge_t *head;
- vertex_t *next;
- };
- // 图结构
- // 总体结构是这样的, 就是链表链链表:
- // holder -> vertex1 -> vertex2 -> vertex3 -> vertex4 -> vertex5...
- // |
- // edge1[edge结构体对象中的adj表示该vertex1和哪一个顶点相连, ex, vertex3, 那么adj就是vertex3的information的data]
- // |
- // edge2[ex, 假如这个边节点表示vertex1和vertex5相连, 那么adj就是vertex5的data]
- // |
- // edge3...
- typedef struct _graph graph_t;
- struct _graph {
- vertex_t *holder;
- int v_cnt;
- int e_cnt;
- };
- // 初始化图, 只是创建一个容器的手柄,
- // 让用户自行添加顶点和边, 图的最终形状通过添加确定
- graph_t *graph_create(void)
- {
- graph_t *thiz = NULL;
- thiz = malloc(sizeof(graph_t));
- if (!thiz)
- return NULL;
- thiz->holder = NULL;
- thiz->v_cnt = 0;
- thiz->e_cnt = 0;
- return thiz;
- }
- void __graph_init_vertex(vertex_t *v, vinfo_t *vinfo)
- {
- memcpy(&v->vinfo, vinfo, sizeof(vinfo_t));
- v->nei_cnt = 0;
- v->head = NULL;
- v->next = NULL;
- v->visited = 0;
- }
- void graph_add_vertex(graph_t *thiz, vinfo_t *vinfo)
- {
- vertex_t **cur = &thiz->holder;
- vertex_t *v = malloc(sizeof(vertex_t));
- if (!v)
- return;
-
- __graph_init_vertex(v, vinfo);
- while (*cur)
- cur = &(*cur)->next;
-
- *cur = v;
- thiz->v_cnt++;
- }
- // key是顶点标记,根据顶点标记从图中[就是顶点链表]搜索到该顶点
- vertex_t *graph_search_vertex(graph_t *thiz, int key)
- {
- vertex_t *t = thiz->holder;
- while (t) {
- if (t->vinfo.data == key)
- return t;
- t = t->next;
- }
- return NULL;
- }
- // 无向图, 添加边, from, to 是顶点标记
- // 如果是有向图就更简单, 只要给from顶点的邻接链表中增加一个边节点即可
- void graph_add_edge(graph_t *thiz, int from, int to, einfo_t *einfo)
- {
- // 首先得到需要增加边的两个顶点
- vertex_t *from_v = graph_search_vertex(thiz, from);
- vertex_t *to_v = graph_search_vertex(thiz, to);
- // 构建edge, 加到from_v的邻接链表中
- edge_t *ef = malloc(sizeof(edge_t));
- if (!ef)
- return;
- ef->einfo = *einfo;
- ef->adj = to;
- ef->next = NULL;
- edge_t **cur = &from_v->head;
- while (*cur)
- cur = &(*cur)->next;
- *cur = ef;
- // 加到to_v的邻接链表中
- edge_t *et = malloc(sizeof(edge_t));
- if (!et)
- {
- free(ef);
- return;
- }
- et->einfo = *einfo;
- et->adj = from;
- et->next = NULL;
- cur = &to_v->head;
- while (*cur)
- cur = &(*cur)->next;
- *cur = et;
- from_v->nei_cnt++;
- to_v->nei_cnt++;
- thiz->e_cnt++;
- }
- void __graph_dfs(graph_t *thiz, int start)
- {
- vertex_t *v = graph_search_vertex(thiz, start);
- if (!v)
- return;
-
- printf("%s ", v->vinfo.name);
- v->visited = 1;
- edge_t *e = v->head;
- while (e)
- {
- v = graph_search_vertex(thiz, e->adj);
- while (v->visited == 0)
- __graph_dfs(thiz, v->vinfo.data);
- e = e->next;
- }
- }
- void graph_dfs(graph_t *thiz, int start)
- {
- vertex_t *v = thiz->holder;
- while (v)
- {
- v->visited = 0;
- v = v->next;
- }
- __graph_dfs(thiz, start);
- printf("\n");
- }
复制代码 PS:代码看上去有点长。耐心点读罢。。。
|
|