美文网首页
图的邻接表创建与遍历

图的邻接表创建与遍历

作者: zhaoyubetter | 来源:发表于2017-02-24 08:27 被阅读142次

对比矩阵创建图##

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

  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 ===================

相关文章

  • 图的邻接表创建与遍历

    对比矩阵创建图## 如果图的边数,比较少,使用矩阵,会有大量空间浪费;这个时候,考虑另外一种存储结构方式,将数组和...

  • 图的遍历

    1.采用深度优先搜索(DFS)遍历图 邻接矩阵: 邻接表: 2.采用广度优先搜索(BFS)遍历图 邻接矩阵: 邻接...

  • 第七章 图

    邻接表定义 邻接表求各点入度 邻接表各点出度 DFS与BFS遍历 已知一个无向图G的邻接表存储表示如下,试写出从顶...

  • 5 图的复习目录

    5.1 图 5.2 图的存储结构 邻接矩阵 邻接表 十字链表 邻接多重链表 5.3 图的遍历 深度优先 广...

  • 数据结构—图的遍历

    根据图的存储方式可分为邻接矩阵的深度优先遍历和邻接表的深度优先遍历。 一、深度优先遍历 1、邻接矩阵的深度优先遍历...

  • 各种DFS

    DFS邻接矩阵遍历图 DFS邻接表遍历图 DFS回溯(不走重复路径) DFS背包(可重复选) DFS背包(不可重复选)

  • 从0开始——图

    1图的概念 2.图的存储结构 1.邻接矩阵 2.邻接表 3.图的遍历 1.2邻接表的深度优先算法 1.3扩展:马踏...

  • 数据结构-图

    图的增删改查 增 邻接表 邻接矩阵 删 改 查 图的遍历 深度优先遍历(DFS) 深度优先搜索法是树的先根遍历的推...

  • 数据结构(三)——图的邻接矩阵的创建及遍历

    图由有穷、非空点集和边集合组成,简写成G(V,E0) 图的创建有多种方法(邻接矩阵、邻接表、十字链表) 图的遍历方...

  • 03.图的深度和广度优先遍历(递归和非递归都有,邻接表和邻接矩阵

    03.图的深度和广度优先遍历(递归和非递归都有,邻接表和邻接矩阵) 图论是一个很重要的工具,这节主要是图的创建和遍...

网友评论

      本文标题:图的邻接表创建与遍历

      本文链接:https://www.haomeiwen.com/subject/iezbwttx.html