对比矩阵创建图##
如果图的边数,比较少,使用矩阵,会有大量空间浪费;
这个时候,考虑另外一种存储结构方式,将数组和链表结合起来来存储;
邻接表的处理:
- 图中的顶点用一个一维数组存储;
- 图中每个顶点Vi的所有邻接点构成一个线性表(单链表)
实现代码
结构:
#define MAX_SIZE 20
// ========= 邻接表 无向 Start ================
// 链表结点 Node
typedef struct LinkNode {
int array_index; // 数组下标
int weight; // 权重
struct LinkNode *next; // 下一个顶点
} LinkNode;
// 图结点
typedef struct GraphNode {
char data; // 结点数据
struct LinkNode *first; // 顶点链表
} GraphNode;
// 图
typedef struct GraphTable {
GraphNode nodes[MAX_SIZE];
int vertexNum, edgeNum; // 顶点数,变数
} GraphTable, *P_GraphTable;
创建表:
// ==== 使用邻接表 来创建图 无向 start ====
void printTable(P_GraphTable *G) {
int i;
LinkNode *node;
// 输出邻接表
printf("------------ 无向邻接表 ----------\n");
for(i=0; i<(*G)->vertexNum; i++) {
node = NULL;
node = (*G)->nodes[i].first;
printf("%d-%c|-",i, (*G)->nodes[i].data);
while( node != NULL && node->array_index >= 0) {
printf("%d-",node->array_index);
node = node->next;
}
printf("\n"); // 换行
}
}
void createTable(P_GraphTable *G) {
(*G) = (P_GraphTable) malloc(sizeof(GraphTable));
int m,n,i;
printf("请输入图的顶点数与边数:");
scanf("%d %d", &m, &n);
getchar();
(*G)->vertexNum = m;
(*G)->edgeNum = n;
// 创建顶点数组 GraphNode
for(m = 0; m<(*G)->vertexNum; m++) {
printf("请输入第 %d 个顶点:", (m+1));
scanf("%c", &(*G)->nodes[m].data);
getchar();
(*G)->nodes[m].first = NULL; // 初始化为空表
}
// 创建边
for(i = 0; i<(*G)->edgeNum; i++) {
printf("请输入第%d条边(Vi,Vj)上的下标i,下标j:\n", (i+1));
scanf("%d %d", &m, &n); // 下标对应顶点
getchar();
LinkNode *e1 = (LinkNode *)malloc(sizeof(LinkNode));
e1->array_index = n; // 设置邻接点下标
e1->next = (*G)->nodes[m].first; // 第一次时,first为NULL,后面会被替换掉
(*G)->nodes[m].first = e1; // 放入图中数组
LinkNode *e2 = (LinkNode *)malloc(sizeof(LinkNode));
e2->array_index = m; // 设置邻接点下标
e2->next = (*G)->nodes[n].first;
(*G)->nodes[n].first = e2;
}
printTable(G);
}
int main(int argc, const char * argv[]) {
P_GraphTable table;
createTable(&table);
return 0;
}
输出如下
请输入图的顶点数与边数:4 5
请输入第 1 个顶点:A
请输入第 2 个顶点:B
请输入第 3 个顶点:C
请输入第 4 个顶点:D
请输入第1条边(Vi,Vj)上的下标i,下标j:
0 1
请输入第2条边(Vi,Vj)上的下标i,下标j:
0 2
请输入第3条边(Vi,Vj)上的下标i,下标j:
1 2
请输入第4条边(Vi,Vj)上的下标i,下标j:
2 3
请输入第5条边(Vi,Vj)上的下标i,下标j:
1 3
------------ 无向邻接表 ----------
0-A|-2-1-
1-B|-3-2-0-
2-C|-3-1-0-
3-D|-1-2-
深度优先遍历(不断访问链表)##
直接访问链表即可;
// 清空已访问过得顶点数组
void clearVisit(P_GraphTable G) {
int i;
for(i=0; i<G->vertexNum; i++) {
visited[i] = FALSE;
}
}
void dfs(P_GraphTable G, int i) {
visited[i] = TRUE;
printf("%c ", G->nodes[i].data);
LinkNode *node = G->nodes[i].first;
while(node) {
if(!visited[node->array_index]) {
dfs(G, node->array_index);
}
node = node->next;
}
}
void dfs_g(P_GraphTable G) {
clearVisit(G);
int i;
for(i=0; i<G->vertexNum; i++) {
if(!visited[i]) { // 连通图,只会执行一次
dfs(G, i);
}
}
}
广度优先遍历 实现代码##
//========= 广度 Start ===================
typedef struct {
int array[MAX_SIZE];
int front;
int rear;
} Queue;
void initQueue(Queue *que) {
que->front = 0;
que->rear = -1;
}
int isQueueEmpty(Queue *que) {
return (que->rear + 1 == que->front || que->front == MAX_SIZE);
}
void insertQueue(Queue *que, int x) {
if(que->rear != MAX_SIZE - 1) { // 未满
que->array[++que->rear] = x;
}
}
int removeQueue(Queue *que) {
return que->array[que->front++];
}
void bfs(P_GraphTable G) {
Queue *que = (Queue *)malloc(sizeof(Queue));
initQueue(que);
clearVisit(G);
int i;
int v;
for(i=0; i<G->vertexNum; i++) {
if(!visited[i]) { // 选取一个未访问的顶点,如果图是连通图,则只执行一次
printf("%c ", G->nodes[i].data);
visited[i] = TRUE;
insertQueue(que, i);
while(!isQueueEmpty(que)) {
v = removeQueue(que);
LinkNode *node = G->nodes[v].first;
while(node) {
if(!visited[node->array_index]) {
insertQueue(que, node->array_index);
visited[node->array_index] = TRUE;
printf("%c ", G->nodes[node->array_index].data);
}
node = node->next;
}
}
}
}
}
//========= 广度 End ===================