知识小结:
(1)链表可以动态扩展和收缩,这是较数组的优点
(2)互联网建模,关节点代表单点故障源,如果该点出错则系统无法通信。因此在设计保持长时间连接的大型网络架构时,很重要的一点就是保证网络中没有关节点。
(3)有向图很适合状态机建模
(4)超图:包含超边,即可以连接任意数量顶点的边
(5)多重图:允许在相同的两个顶点间有多条边存在
(6)邻接矩阵表示法:V*V阶矩阵,V 顶点个数,如果顶点u,v之间存在一条边,则在矩阵[u,v]处设置一个标志
应用:
1、计算网格跳数-采用广度优先搜索确定节点之间的最小跳数
2、广度优先搜索代码
数据结构
这里的BfsVertex,即AdjList中*vertex指向的内容。包含节点数据、颜色、跳数。
typedef struct BfsVertex_{
void *data;
VertexColor color;
int hops;
}BfsVertex;
//start:指定起始点,hops:返回起始点能够到达的所有点
int bfs(Graph *graph, BfsVertex *start, List *hops)
{
Queue queue;
AdjList *adjlist, *clr_adjlist;
BfsVertex *clr_vertex, *adj_vertex;
LIST_ELEMENT *element, *member;
//找到起点涂灰,跳数为0,其余图白,跳数为-1
for(element = list_head(graph->adjlists); element != NULL; element = list_next(element))
{
clr_vertex = ((AdjList *)element->data)->vertex;
if(graph->match(clr_vertex, start))
{
clr_vertex->color = gray;
clr_vertex->hops = 0;
}
else
{
clr_vertex->color = white;
clr_vertex->hops = -1;
}
}
queue_init(&queue,NULL);
//找到与起点对应的信息存于clr_adjlist
if(graph_adjlist(graph, start, &clr_adjlist) != 0)
{
queue_destroy(&queue);
return -1;
}
//起点入队列
if(queue_enqueue(&queue, clr_adjlist) != 0)
{
queue_destroy(&queue);
return -1;
}
while(queue_size(&queue) > 0)
{
//起点出队列,把起点的邻接点涂灰,hops加1如队列
//之前已经涂灰的不会如队列,这就避免节点重复
adjlist = queue_peek(&queue);
for(member = list_head(&adjlist->adjacent); member != NULL; member = list_next(element))
{
adj_vertex = member->data;
if(graph_adjlist(graph, adj_vertex, &clr_adjlist) != 0)
{
queue_destroy(&queue);
return -1;
}
clr_vertex = clr_adjlist->vertex;
if(clr_vertex->color == white)
{
clr_vertex->color = gray;
clr_vertex->hops = ((BfsVertex *)(adjlist->vertex)->hops + 1);
if(queue_enqueue(&queue, clr_adjlist) != 0)
{
queue_destroy(&queue);
return -1;
}
}
}
//出队列一个二级节点,涂黑,以这个图黑的节点取代起始节点的地位,再次寻找它的邻接点入队列(先进先出)
//然后再出第二个二级节点,涂黑重复
if(queue_dequeue(&queue, (void **)&adjlist) == 0)
{
((BfsVertex *)adjlist->vertex)->color = black;
}
else
{
queue_destroy(&queue);
return -1;
}
}
queue_destroy(&queue);
list_init(hops, NULL);
//把跳数不为-1的点(由起始点能到达的点)放到链表hops中
for(element = list_head(graph->adjlists); element != NULL; element = list_next(element))
{
clr_vertex = ((AdjList *)element->data)->vertex;
if(clr_vertex->hops != -1)
{
if(list_ins_next(hops, list_tail(hops), clr_vertex) != 0)
{
list_destroy(hops);
return -1;
}
}
}
return 0;
}
3、拓扑排序-深度优先搜索
某些阶段必须在其他阶段之前完成,采用优先级图建模。在优先级图中,顶点代表任务,边代表任务之间的依赖关系。
递归到最深处的点,涂黑、压栈
(1)数据结构
typedef struct DfsVertex_{
void *data;
VertexColor color;
}DfsVertex;
(2)递归深度搜索
//ordered:存放由最深处点开始的链路
int dfs_main(Graph *graph, AdjList *adjlist, List *ordered)
{
AdjList *clr_adjlist;
BfsVertex *clr_vertex, *adj_vertex;
LIST_ELEMENT *member;
((DfsVertex *)adjlist->vertex)->color = gray;
//遍历当前节点的邻节点
for(member = list_head(&adjlist->adjacent); member != NULL; member = list_next(member))
{
adj_vertex = list_data(member);
if(graph_adjlist(graph, adj_vertex, &clr_adjlist) != 0)
return -1;
clr_vertex = clr_adjlist->vertex;
//往深处递归
if(clr_vertex->color == white)
{
if(dfs_main(graph, clr_adjlist, ordered) != 0)
return -1;
}
}
//第一个涂黑并压栈的其实是最深处的点
((DfsVertex *)adjlist->vertex)->color = black;
if(list_ins_next(ordered, NULL, (DfsVertex *)adjlist->vertex) != 0)
return -1;
return 0;
}
(3)初始化,对每个白点执行深度搜索
int dfs(Graph *graph, List *ordered)
{
DfsVertex *vertex;
LIST_ELEMENT *elememt;
for(elememt = list_head(graph->adjlists); elememt != NULL; elememt = list_next(elememt))
{
vertex = ((AdjList *)list_data(elememt))->vertex;
vertex->color = white;
}
list_init(ordered, NULL);
for(elememt = list_head(graph->adjlists); elememt != NULL; elememt = list_next(elememt))
{
vertex = ((AdjList *)list_data(elememt))->vertex;
if(vertex->color == white)
{
if(dfs_main(graph, (AdjList *)list_data(elememt), ordered) != 0)
{
list_destroy(ordered);
return -1;
}
}
}
return 0;
}