图的创建与遍历
1.选择一种存储结构实现有向图的创建
首先,采用邻接矩阵创建图,由于不需要考虑权值问题,因此在邻接矩阵中,0表示没有边,1表示有边,通过两层循环从矩阵转为邻接表的存储结构。邻接表中有两种节点类型,顶点节点按照序号顺序存储在一个数组中,包含序号域和边节点域两个属性,而边节点以相应顶点节点作为头节点构成链式结构,每一个边节点包含序号域、边节点域与顶点节点域(指向与之序号相同的顶点节点方面后续的遍历操作)。
在实际操作中,利用数组存储顶点节点总会出现内存访问冲突的问题,所以改用了链结构存储顶点节点。
//邻接矩阵
int adjacency_matrix[size][size] = {
{0, 1, 1, 1, 0, 0, 0},
{0, 0, 1, 0, 1, 0, 0},
{0, 0, 0, 0, 1, 1, 0},
{0, 0, 1, 0, 0, 1, 0},
{0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 1, 0, 1},
{0, 0, 0, 0, 0, 0, 0}
};
//顶点节点
typedef struct vertexNode {
int order;
int flag;
struct edgeNode* next_edge = NULL;
struct vertexNode* next_vertex = NULL;
}vertexNode;
//顶点节点初始化
vertexNode* vertex_node_initialize() {
vertexNode* vertex_node = (vertexNode*)malloc(sizeof(vertexNode));
vertex_node->next_edge = NULL;
vertex_node->next_vertex = NULL;
return vertex_node;
}
//边节点
typedef struct edgeNode {
int order;
struct edgeNode* next_edge;
struct vertexNode* vertex_node;
}edgeNode;
//边节点初始化
edgeNode* edge_node_initialize() {
edgeNode* edge_node = (edgeNode*)malloc(sizeof(edgeNode));
edge_node->next_edge = NULL;
edge_node->vertex_node = NULL;
return edge_node;
}
//图的邻接表创建
vertexNode* create_graph() {
vertexNode* vertex_head = vertex_node_initialize();
vertex_head->order = -1;
vertexNode* vertex_ptr = vertex_head;
for (int i = 0; i < size; i++) {
vertexNode* vertex_node = vertex_node_initialize();
vertex_ptr->next_vertex = vertex_node;
vertex_ptr = vertex_node;
vertex_node->order = i;
vertex_node->flag = 0;
}
vertexNode* vertex_node = vertex_head;
for (int row = 0; row < size; row++) {
vertex_node = vertex_node->next_vertex;
edgeNode* edge_head = edge_node_initialize();
edge_head->order = -1;
vertex_node->next_edge = edge_head;
edgeNode* edge_ptr = edge_head;
for (int column = 0; column < size; column++) {
if (adjacency_matrix[row][column] > 0) {
edgeNode* edge_node = edge_node_initialize();
edge_ptr->next_edge = edge_node;
edge_ptr = edge_ptr->next_edge;
edge_node->order = column;
edge_node->vertex_node = find_node(vertex_head, column);
}
}
}
return vertex_head;
}
//寻找顶点节点
vertexNode* find_node(vertexNode* vertex_head, int order) {
vertexNode* p = vertex_head->next_vertex;
while (1) {
if (p->order == order) return p;
else p = p->next_vertex;
}
}
2. 利用队列实现从序号最小的点开始,对图进行广度优先遍历,将遍历结果输出在屏幕上
访问第一个顶点节点并将该顶点连通的所有顶点节点加入队列。这里是通过每一个顶点的边节点域来确定顶点之间的连通性,又因为在之前建立了边节点与对应顶点节点的连接关系,因此可以直接可以通过边节点域访问对应顶点节点然后将顶点节点加入到队列中。然后依次出队访问出队顶点节点并做同样的操作,直到栈为空。另外由于这是一个连通图,所以不需要考虑对顶点节点依次作为起始点遍历。
//广度优先遍历
void breadth_first_traversal(vertexNode* vertex_head, void(*fun)(vertexNode*)) {
queue* queues = queue_initialize();
if (vertex_head->next_vertex != NULL) enter_queue(queues, vertex_head->next_vertex);
while (queues->front != queues->rear) {
vertexNode* vertex_node = delete_queue(queues);
visit(vertex_node);
edgeNode* edge_node = vertex_node->next_edge->next_edge;
while (edge_node != NULL) {
if (edge_node->vertex_node->flag == 0) enter_queue(queues, edge_node->vertex_node);
edge_node = edge_node->next_edge;
}
}
}
//访问打印节点
void visit(vertexNode* vertex_node) {
if (vertex_node->flag != 1) printf("%d", vertex_node->order);
vertex_node->flag = 1;
}
3.从序号最小的点开始,用递归算法实现图的深度优先搜索遍历,将遍历结果输出在屏幕上
采用递归的思想,访问起始顶点节点并对与顶点节点连通的顶点节点做深度优先遍历。
//寻找顶点节点
void deepth_first_traversal(vertexNode* vertex_node, void(*fun)(vertexNode*)) {
fun(vertex_node);
edgeNode* edge_node = vertex_node->next_edge;
while (edge_node->next_edge != NULL) {
edge_node = edge_node->next_edge;
deepth_first_traversal(edge_node->vertex_node, visit);
}
}
4.判断图中任意两点是否有路径,如果有路径,将路径输出在屏幕上。
不需要考虑最短路径问题,所以对起点进行深度优先遍历。在这里使用的是非递归的深度优先遍历,用栈结构存储带访问的深度优先遍历节点,并将路径点存储在另外一个栈结构中,当找到终点后,对存储路径点的栈结构进行倒序输出。
//定义栈结构
typedef struct stack {
int top;
vertexNode* vertexs[2 * size];
}stack;
//栈的初始化
stack* stack_initialize() {
stack* stacks = (stack*)malloc(sizeof(stack));
stacks->top = -1;
return stacks;
}
//进栈
void push(stack* stacks, vertexNode* vertex_node) {
stacks->top++;
stacks->vertexs[stacks->top] = vertex_node;
}
//出栈
vertexNode* pop(stack* stacks) {
vertexNode* vertex_node = stacks->vertexs[stacks->top];
stacks->top--;
return vertex_node;
}
//路径打印
void path_print(stack* stacks, int start, int end) {
if (stacks->top == -1) printf("起点%d到终点%d无路径", start, end);
else {
printf("\n起点%d到终点%d存在路径:", start, end);
for (int i = 0; i <= stacks->top; i++) printf("%d", stacks->vertexs[i]->order);
}
}
//路径查找
void find_path(vertexNode* vertex_head, int start, int end) {
vertexNode* vertex_ptr = vertex_head->next_vertex, * vertex_start = NULL, * vertex_end;
while (vertex_ptr != NULL) {
if (vertex_ptr->order == start) vertex_start = vertex_ptr;
else if (vertex_ptr->order == end) vertex_end = vertex_ptr;
vertex_ptr = vertex_ptr->next_vertex;
}
stack* path_stack = stack_initialize();
stack* find_stack = stack_initialize();
if (vertex_start) push(find_stack, vertex_start);
while (find_stack->top != -1) {
vertexNode* vertex_node = pop(find_stack);
push(path_stack, vertex_node);
edgeNode* edge_node = vertex_node->next_edge->next_edge;
while (edge_node != NULL) {
push(find_stack, edge_node->vertex_node);
if (edge_node->order == end) {
if (vertex_node->order == 0) push(path_stack, edge_node->vertex_node);
path_print(path_stack, start, end);
return;
}
edge_node = edge_node->next_edge;
}
}
}
最终效果