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;
    }



  • 相关阅读:
    Apache Spark 2.2.0 中文文档
    Apache Spark 2.2.0 中文文档
    Apache Spark 2.2.0 中文文档
    Apache Spark 2.2.0 中文文档
    Apache Spark 2.2.0 中文文档
    Apache Spark RDD(Resilient Distributed Datasets)论文
    Apache Spark 2.2.0 中文文档
    Apache Spark 2.2.0 中文文档
    【机器学习实战】第10章 K-Means(K-均值)聚类算法
    [译]flexbox全揭秘
  • 原文地址:https://www.cnblogs.com/abc123456789/p/3433425.html
Copyright © 2011-2022 走看看