C語言鄰接表實現圖的任意兩點間所有路徑
阿新 • • 發佈:2019-02-13
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEBUG 1
#if DEBUG
#define PRINTF printf
#else
#define PRINTF
#endif
//最大節點個數
#define MAX_VEX (256)
//標記節點是否被訪問過(被加入路徑)
char visited[MAX_VEX+1];
//記錄各節點在路徑中的下一節點
char path_next[MAX_VEX];
//使用陣列實現棧的功能,用於記錄當前走的路徑
int path_record[MAX_VEX];
//表示path_record陣列最大索引,來標識當前的棧頂位置
int g_idx;
//邊
typedef struct edge_node
{
int idx;
struct edge_node *next;
}edge_node_t;
//節點
typedef struct vertex_node
{
char data;
edge_node_t *first_edge;
}vertex_node_t, vertex_node_list[MAX_VEX];
//圖
typedef struct graph
{
vertex_node_list list;
int num_vex;
int num_edge;
}graph_t;
void print_graph(graph_t *g)
{
int i;
edge_node_t *p;
for(i=0; i<g->num_vex; i++)
{
printf("<%d> : %c ", i, g->list[i].data);
if(NULL == g->list[i].first_edge)
printf(" >> NULL");
else
{
for(p=g->list[i].first_edge; p!=NULL; p=p->next)
{
printf (" >> <%d> %c", p->idx, g->list[p->idx].data);
}
}
printf("\n");
}
}
void free_graph(graph_t *g)
{
int i;
edge_node_t *p, *q;
for(i=0; i<g->num_vex; i++)
{
p = g->list[i].first_edge;
while(p)
{
q = p->next;
free(p);
p = q;
}
}
}
int create_graph(graph_t *g)
{
int i, j, k;
edge_node_t *p, *q;
int ret;
//輸入節點數和邊數
PRINTF("input num of vertex and num of edge : ");
ret = scanf("%d %d\n", &(g->num_vex), &(g->num_edge));
PRINTF("ret = %d, num_vex : %d, num_edge : %d\n", ret, g->num_vex, g->num_edge);
//輸入節點資訊
PRINTF("input data of vertex:\n");
for(i=0; i<g->num_vex; i++)
{
PRINTF("vertex %d : ", i+1);
ret = scanf("%c\n", &(g->list[i].data));
PRINTF("ret = %d, %d : %d\n", ret, i, g->list[i].data);
g->list[i].first_edge = NULL;
}
//輸入邊資訊;當前實現按照無向圖建立
for(k=0; k<g->num_edge; k++)
{
PRINTF("input the index of (vi, vj) : ");
ret = scanf("%d %d\n", &i, &j);
PRINTF("ret : %d, i : %d, j : %d\n", ret, i, j);
p = (edge_node_t *)malloc(sizeof(edge_node_t));
memset(p, 0x0, sizeof(edge_node_t));
p->idx = j;
#if 0
p->next = g->list[i].first_edge;
g->list[i].first_edge = p;
#else
if(g->list[i].first_edge == NULL)
g->list[i].first_edge = p;
else
{
for(q=g->list[i].first_edge; q->next!=NULL; q=q->next);
q->next = p;
}
#endif
p = (edge_node_t *)malloc(sizeof(edge_node_t));
memset(p, 0x0, sizeof(edge_node_t));
p->idx = i;
#if 0
p->next = g->list[j].first_edge;
g->list[j].first_edge = p;
#else
if(g->list[j].first_edge == NULL)
g->list[j].first_edge = p;
else
{
for(q=g->list[j].first_edge; q->next!=NULL; q=q->next);
q->next = p;
}
#endif
}
}
//查詢與當前節點連線的下一個可用的節點
edge_node_t *neighbour(graph_t *g, int idx)
{
edge_node_t *p;
p = g->list[idx].first_edge;
while(NULL != p)
{
if(visited[p->idx] == 1)//已在路徑中
{
p = p->next;
}
else
{
if(-1 == path_next[idx])//未被路徑訪問過
{
while(p!=NULL && visited[p->idx]==1)
p = p->next;
return p;
}
else if(p->idx == path_next[idx])//被上一次路徑訪問過
{
p = p->next;
while(p!=NULL && visited[p->idx]==1)
p = p->next;
return p;
}
else//被以前的路徑訪問過
{
p = p->next;
}
}
}
}
/*****************************************************************************
函 數 名 : all_path
功能描述 : 在圖g中查詢起始節點start到結束節點end之間的所有路徑並輸出
輸入引數 : graph_t *g 圖的鄰接表儲存結構
int start 起始節點
int end 結束節點
輸出引數 : 無
返 回 值 :
*****************************************************************************/
void all_path(graph_t *g, int start, int end)
{
int i, cur_vex;
edge_node_t *p;
while(g_idx >= 0)
{
cur_vex = path_record[g_idx];
if(cur_vex == end)//已走到結束節點,輸出完整路徑
{
PRINTF("%d -> %d : ", start, end);
for(i=0; i<=g_idx; i++)
{
if(i == 0)
PRINTF("<%d> %c", path_record[i], g->list[path_record[i]].data);
else
PRINTF(" >> <%d> %c", path_record[i], g->list[path_record[i]].data);
}
PRINTF("\n");
//結束節點出棧
visited[end] = 0;
path_record[g_idx] = -1;
path_next[end] = -1;
g_idx--;
}
else
{
p = neighbour(g, cur_vex);
if(p != NULL)
{
//有可走的路徑下一跳,當前節點入棧
path_next[cur_vex] = p->idx;
g_idx++;
path_record[g_idx] = p->idx;
visited[p->idx] = 1;
}
else
{
//沒有可走的路徑下一跳,當前節點出棧
visited[cur_vex] = 0;
path_record[g_idx] = -1;
path_next[cur_vex] = -1;
g_idx--;
}
}
}
}
int main()
{
graph_t g;
int start, end;
int ret, i;
memset(&g, 0x0, sizeof(g));
#if DEBUG
freopen("data.txt", "r", stdin);
#endif
create_graph(&g);
#if DEBUG
PRINTF("[%s][%d] print_graph : \n", __FUNCTION__, __LINE__);
print_graph(&g);
#endif
//初始化
for(i=0; i<g.num_vex; i++)
{
visited[i] = 0;
path_next[i] = -1;
path_record[i] = -1;
}
g_idx = 0;
//輸入起始和結束節點
PRINTF("input start and end node index : ");
ret = scanf("%d %d\n", &start, &end);
PRINTF("ret : %d, start : %d, end : %d\n", ret, start, end);
//起始節點入棧
path_record[g_idx] = start;
visited[start] = 1;
all_path(&g, start, end);
free_graph(&g);
return 0;
}
// 樣例輸入:
/*
8 9
a
b
c
d
e
f
g
h
0 1
0 2
1 3
1 4
3 7
4 7
2 5
2 6
5 6
3 6
*/
/*
8 9
0
1
2
3
4
5
6
7
0 1
0 2
1 3
1 4
3 7
4 7
2 5
2 6
5 6
3 6
*/
/*
9 11
0
1
2
3
4
5
6
7
8
0 1
0 2
1 3
1 4
3 7
4 7
2 5
2 6
5 6
5 8
6 8
3 6
*/