zoukankan      html  css  js  c++  java
  • 图的表示及遍历

    1. 图的表示

    1)临接矩阵

    使用二维数组arr[N][N]表示一个图。

    a. N 为图的顶点个数,矩阵的对角线全为0。

    b. 两个顶点连通的话,矩阵的值为1

    c. 某一行的和表示该顶点的出度。某一列的和表示该顶点的入度

    d. 有权值的图,矩阵元素不再是0,1表示是否连通,而是把元素值表示为权值。不存在的边,权值记录为;对角线上的权值为0

    使用临接矩阵表示图,直观方便,缺点是占用空间大,因为需要 N*N 个空间。对于稀疏图来说,这比较浪费空间。

    2) 临接表

    a. 使用数组保存顶点

    b. 每个顶点的所有临接点组成一个线性表,挂在数组后面。

    这种方法类似散列表的开链法。

    优点是节省空间,顶点的出度就在链表上,但是要查找入度的话,需要遍历整个图

    2. 图的遍历

    1)广度优先

    先遍历图的所有临节点,再依次遍历临接点的临接点

    2)深度优先

    从某一个节点出发,一直走下去,直到找不到临接点。再从其他节点出发,继续一条道路走到黑

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <assert.h>
    
    
    enum Ecolor
    {
        WHITE = 0,
        GRAY,
        BLACK
    };
    
    // 这里使用临接表表示图
    struct graph_node_s
    {
        enum Ecolor color;  // 节点颜色,用来标识该顶点是否别遍历过
        int d;
        int ftime;          // 节点访问结束时间
        int dtime;          // 节点访问开始时间
        struct graph_node_s *next;
    };
    typedef struct graph_node_s graph_node_t;
    
    struct graph_s
    {
        int vertice;        // 顶点数
        int edge;           // 边数
        graph_node_t *bucket[1];    // 保存顶点节点
    };
    typedef struct graph_s graph_t;
    
    // 广度优先遍历使用了队列保存临接点
    struct queue_node_s
    {
        void *d;
        struct queue_node_s *prev;
        struct queue_node_s *next;
    };
    typedef struct queue_node_s queue_node_t;
    
    struct queue_s
    {
        queue_node_t *sentinel;
    };
    typedef struct queue_s queue_t;
    
    
    queue_t *queue_create(void)
    {
        queue_t *queue = (queue_t*)malloc(sizeof(queue_t));
        assert(queue);
    
        queue->sentinel = (queue_node_t*)malloc(sizeof(queue_node_t));
        assert(queue->sentinel);
    
        queue->sentinel->next = queue->sentinel;
        queue->sentinel->prev = queue->sentinel;
    
        return queue;
    }
    
    void queue_destroy(queue_t *q)
    {
        assert(q);
    
        queue_node_t *nd = q->sentinel->next;
        while (nd != q->sentinel)
        {
            queue_node_t *tmp = nd;
            nd = nd->next;
            free(tmp);
        }
        free(nd);
        free(q);
    }
    
    void queue_push(queue_t *q, void *value)
    {
        assert(q);
        assert(value);
    
        queue_node_t* nd = (queue_node_t*)malloc(sizeof(queue_node_t));
        assert(nd);
    
        nd->d = value;
        nd->next = q->sentinel;
        nd->prev = q->sentinel->prev;
        q->sentinel->prev->next = nd;
        q->sentinel->prev = nd;
    }
    
    void queue_pop(queue_t *q)
    {
        assert(q);
    
        queue_node_t *tmp = q->sentinel->next;
    
        if (tmp != q->sentinel)
        {
            q->sentinel->next = q->sentinel->next->next;
            q->sentinel->next->prev = q->sentinel;
            free(tmp);
        }
    }
    
    void *queue_front(queue_t *q)
    {
        assert(q);
    
        return q->sentinel->next->d;
    }
    
    int queue_empty(queue_t *q)
    {
        assert(q);
    
        return q->sentinel->next == q->sentinel;
    }
    
    graph_t *graph_create(int vertice)
    {
        graph_t *g = (graph_t*)malloc(sizeof(graph_t) + (vertice-1)*sizeof(graph_node_t*));
        assert(g);
    
        g->vertice = vertice;
        g->edge = 0;
        for (int i = 0; i < vertice; ++i)
        {
            g->bucket[i] = (graph_node_t*)malloc(sizeof(graph_node_t));
            assert(g->bucket[i]);
    
            g->bucket[i]->d = i;
            g->bucket[i]->color = WHITE;
            g->bucket[i]->next = NULL;
        }
    
        return g;
    }
    
    void graph_destroy(graph_t *g)
    {
        assert(g);
    
        for (int i = 0; i < g->vertice; ++i)
        {
            graph_node_t *head = g->bucket[i];
            while (head)
            {
                graph_node_t *tmp = head;
                head = head->next;
                free(tmp);
            }
        }
        free(g);
    }
    
    void graph_add_edge(graph_t *g, int src, int dst)
    {
        assert(g);
        assert(src < g->vertice);
        assert(dst < g->vertice);
    
        graph_node_t *nd = (graph_node_t*)malloc(sizeof(graph_node_t));
        assert(nd);
        nd->d = dst;
        nd->color = WHITE;
        nd->next = g->bucket[src]->next;
        g->bucket[src]->next = nd;
    }
    
    static void _graph_dfs(graph_t *g, int index, int *time)
    {
        assert(g);
        assert(time);
        assert(index < g->vertice);
    
        (*time)++;
        printf("%d ", g->bucket[index]->d);
        g->bucket[index]->color = GRAY;
        g->bucket[index]->dtime = *time;
    
        graph_node_t *tmp = g->bucket[index]->next;
        while (tmp)
        {
            if (g->bucket[tmp->d]->color == WHITE)
            {
                // 对临接点进行深度遍历
                _graph_dfs(g, tmp->d, time);
            }
            tmp = tmp->next;
        }
    
        g->bucket[index]->color = BLACK;
        (*time)++;
        g->bucket[index]->ftime = *time;
    }
    
    // 深度优先遍历
    void graph_dfs(graph_t *g)
    {
        assert(g);
    
        int time = 0;
        for (int i = 0; i < g->vertice; ++i)
        {
            if (g->bucket[i]->color == WHITE)
            {
                _graph_dfs(g, i, &time);
            }
        }
    }
    
    // 广度优先遍历
    void graph_bfs(graph_t *g, int index)
    {
        assert(g);
        assert(index < g->vertice);
    
        queue_t *q = queue_create();
    
        queue_push(q, g->bucket[index]);
        while (!queue_empty(q))
        {
            graph_node_t *nd = queue_front(q);
            if (g->bucket[nd->d]->color == WHITE)
            {
                printf("%d ", nd->d);
                g->bucket[nd->d]->color = BLACK;
    
                graph_node_t *head = g->bucket[nd->d]->next;
                while (head)
                {
                    // 所有临接点入队
                    queue_push(q, g->bucket[head->d]);
                    head = head->next;
                }
            }
            queue_pop(q);
        }
    
        queue_destroy(q);
    }
    
    int main()
    {
        graph_t *g = graph_create(6);
    
        graph_add_edge(g, 0, 1);
        graph_add_edge(g, 2, 3);
        graph_add_edge(g, 4, 5);
        graph_add_edge(g, 3, 5);
        
    
        graph_bfs(g, 0);
    
        graph_destroy(g);
    
        return 0;
    }
  • 相关阅读:
    eclipse用法和技巧
    eclipse常用快捷键集锦
    移动端input的虚拟键盘影响布局
    使用github page + Hexo搭建个人博客折腾记
    javascript数组的排序(sort,冒泡)
    响应式布局与媒体查询
    css属性选择器诸如Class^=,Class*= ,Class$=释义
    怎么预览 GitHub 项目里的网页或 Demo
    常见浏览器的兼容问题(一)
    jQuery常用交互效果
  • 原文地址:https://www.cnblogs.com/zuofaqi/p/9966466.html
Copyright © 2011-2022 走看看