zoukankan      html  css  js  c++  java
  • 数据结构之图的链表表示

    本代码完全来自于http://blog.chinaunix.net/uid-24774106-id-3505579.html

    代码写的非常专业,同时也有一些非常巧妙的思想,例如如何在不确定图顶点数目的情况动态分配,同时还能二分查找

    贴上全部代码,供大家赏阅

    代码包含两个文件,头文件graph.h和一个cpp文件

    graph.h内容如下

    #ifndef __GRAPH_H__
    #define __GRAPH_H__
    
    typedef struct graph *Graph;
    
    Graph graph_create(int n);
    void graph_destroy(Graph);
    void graph_add_edge(Graph, int source, int sink);
    int graph_vertex_count(Graph);
    int graph_edge_count(Graph);
    int graph_out_degree(Graph, int source);
    int graph_has_edge(Graph, int source, int sink);
    void graph_foreach(Graph g, int source,
            void (*f)(Graph g, int source, int sink, void *data),
            void *data);
    
    #endif


    project1.cpp文件内容如下

    // project1.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <stdlib.h>
    #include <assert.h>
    #include "graph.h"
    
    /* 代码摘自一位yale前辈 */
    
    struct graph {
        int vexnum;  /* number of vertices */
        int edgenum;  /* number of edges */
        struct successors {
            int size;        /* number of successors,即出度数*/
            int capacity;    /* number of slots in array,出度数组的长度,当空间不够,它就会两倍增加*/
            char is_sorted;        /* true if list is already sorted */
            int list[1];    //出度数组,为什么只有一个元素还是用数组?是为了实现动态增加
                                                           
        } *alist[1];//alist数组相当于顶点链表,n个顶点就有n个元素,这里同样是为了动态增加
    };
    
    /* create a new graph with n vertices labeled 0..n-1 and no edges */
    Graph graph_create(int n)
    {
        Graph g;
        int i;
    
        //新增一个graph空间和n-1个successors指针,算上graph中的一个successors指针就有n个了
        g = (Graph)malloc(sizeof(struct graph) + sizeof(struct successors *) * (n-1));
    
        //程序中大量使用assert,其作用是如果它的条件返回错误,则终止程序执行
        assert(g);
    
        g->vexnum = n;
        g->edgenum = 0;
    
        for(i = 0; i < n; i++) {
            //顶点链表
            g->alist[i] = (graph::successors*)malloc(sizeof(struct graph::successors));
            assert(g->alist[i]);
    
            g->alist[i]->size = 0;
            g->alist[i]->capacity = 1;
            g->alist[i]->is_sorted= 1;
            //g->alist[i]->list[1]暂不确定
        }
        
        return g;
    }
    
    /* free all space used by graph */
    void graph_destroy(Graph g)
    {
        int i;
        for(i = 0; i < g->vexnum; i++)
            free(g->alist[i]);
        free(g);
    }
    
    /* 为graph添加边,这里是单向边,仅<u,v> */
    void graph_add_edge(Graph g, int u, int v)
    {
        assert(u >= 0);
        assert(u < g->vexnum);
        assert(v >= 0);
        assert(v < g->vexnum);
    
        /* do we need to grow the list? */
        while(g->alist[u]->size >= g->alist[u]->capacity) {
            g->alist[u]->capacity *= 2;//容量两倍增加的方式
            g->alist[u] =(graph::successors*)realloc(g->alist[u], sizeof(graph::successors) + sizeof(int) * (g->alist[u]->capacity - 1));
        }
    
        /* now add the new sink */
        g->alist[u]->list[g->alist[u]->size++] = v;
        g->alist[u]->is_sorted = 0;
    
        /* bump edge count */
        g->edgenum++;
    }
    
    /* return the number of vertices in the graph */
    int graph_vertex_count(Graph g)
    {
        return g->vexnum;
    }
    
    /* return the number of vertices in the graph */
    int graph_edge_count(Graph g)
    {
        return g->edgenum;
    }
    
    /* return the out-degree of a vertex */
    int graph_out_degree(Graph g, int source)
    {
        assert(source >= 0);
        assert(source < g->vexnum);
    
        return g->alist[source]->size;
    }
    
    /* when we are willing to call bsearch,二分查找 */
    #define BSEARCH_THRESHOLD (10)
    
    static int intcmp(const void *a, const void *b)
    {
        return *((const int *) a) - *((const int *) b);
    }
    
    /* return 1 if edge (source, sink) exists), 0 otherwise */
    int graph_has_edge(Graph g, int source, int sink)
    {
        int i;
    
        assert(source >= 0);
        assert(source < g->vexnum);
        assert(sink >= 0);
        assert(sink < g->vexnum);
    
        //如果该顶点出度数超过10,才使用二分查找
        if(graph_out_degree(g, source) >= BSEARCH_THRESHOLD) {
            if(! g->alist[source]->is_sorted) {
                qsort(g->alist[source]->list,
                        g->alist[source]->size,
                        sizeof(int),
                        intcmp);
            }
            
            /* call bsearch to do binary search for us */
            return 
                bsearch(&sink,
                        g->alist[source]->list,
                        g->alist[source]->size,
                        sizeof(int),
                        intcmp)
                != 0;
        } else {
            /* just do a simple linear search */
            /* we could call lfind for this, but why bother? */
            for(i = 0; i < g->alist[source]->size; i++) {
                if(g->alist[source]->list[i] == sink) return 1;
            }
            /* else */
            return 0;
        }
    }
    
    /* invoke f on all edges (u,v) with source u */
    /* supplying data as final parameter to f */
    //这里注意回调函数的使用
    void
    graph_foreach(Graph g, int source,
        void (*f)(Graph g, int source, int sink, void *data),
        void *data)
    {
        int i;
    
        assert(source >= 0);
        assert(source < g->vexnum);
    
        for(i = 0; i < g->alist[source]->size; i++) {
            f(g, source, g->alist[source]->list[i], data);
        }
    }
    #define TEST_SIZE (6)
    
    //static使得本函数本文件可见
     static void
    match_sink(Graph g, int source, int sink, void *data)
    {
        assert(data && sink == *((int *) data));
    }
    
     //这个函数有什么用?
    static int node2dot(Graph g)
    {
        assert(g != NULL);
        return 0;
    }
    
    static void print_edge2dot(Graph g,int source, int sink, void *data)
    {
        fprintf(stdout,"%d->%d;n",source,sink);
    }
    //打印所有的边
    static int edge2dot(Graph g)
    {
        assert(g != NULL);
        int idx = 0;
        int node_cnt = graph_vertex_count(g);
        for(idx = 0;idx<node_cnt; idx++)
        {
            graph_foreach(g,idx,print_edge2dot,NULL);
        }
        return 0;
    }
    
    int graph2dot(Graph g)
    {
        fprintf(stdout,"digraph{");
        node2dot(g);
        edge2dot(g);
        fprintf(stdout,"}n");
        return 0;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        Graph g;
        int i;
        int j;
    
        g = graph_create(TEST_SIZE);
    
        assert(graph_vertex_count(g) == TEST_SIZE);
    
        /* check it's empty */
        for(i = 0; i < TEST_SIZE; i++) {
            for(j = 0; j < TEST_SIZE; j++) {
                assert(graph_has_edge(g, i, j) == 0);
            }
        }
    
        /* check it's empty again */
        for(i = 0; i < TEST_SIZE; i++) {
            assert(graph_out_degree(g, i) == 0);
            graph_foreach(g, i, match_sink, 0);
        }
    
        /* check edge count */
        assert(graph_edge_count(g) == 0);
    
        //添加边<u,v>,if u<v
        for(i = 0; i < TEST_SIZE; i++) {
            for(j = 0; j < TEST_SIZE; j++) {
                if(i < j) graph_add_edge(g, i, j);
            }
        }
    
    
        for(i = 0; i < TEST_SIZE; i++) {
            for(j = 0; j < TEST_SIZE; j++) {
                assert(graph_has_edge(g, i, j) == (i < j));
            }
        }
        assert(graph_edge_count(g) == (TEST_SIZE*(TEST_SIZE-1)/2));
    
        //打印图
        graph2dot(g);
        /* free it
         * */
        graph_destroy(g);
    
        return 0;
    }



  • 相关阅读:
    我的省选 Day -9
    我的省选 Day -10
    我的省选 Day -11
    我的省选 Day -12
    我的省选 Day -13
    [NOI2013]快餐店
    我的省选 Day -14
    杭电多校2020第7场-E Expectation
    「联合省选2020」组合数问题
    UR#19 通用评测号
  • 原文地址:https://www.cnblogs.com/abc123456789/p/3433425.html
Copyright © 2011-2022 走看看