图的邻接表创建与遍历

对比矩阵创建图##

如果图的边数,比较少,使用矩阵,会有大量空间浪费;
这个时候,考虑另外一种存储结构方式,将数组和链表结合起来来存储;
邻接表的处理:

  1. 图中的顶点用一个一维数组存储;
  2. 图中每个顶点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 ===================
点赞