gml文件格式解析程序详解之源文件
2013-01-17 13:47
381 查看
// Functions to read a network stored in a GML file into a NETWORK struct // // Mark Newman 11 AUG 06 // // To use this software, #include "readgml.h" at the head of your program // and then call the following. // // Function calls: // int read_network(NETWORK *network, FILE *stream) // -- Reads a network from the FILE pointed to by "stream" into the // structure "network". For the format of NETWORK structs see file // "network.h". Returns 0 if read was successful. // void free_network(NETWORK *network) // -- Destroys a NETWORK struct again, freeing up the memory // Inclusions #include <stdlib.h> #include <stdio.h> #include <string.h> #include "network.h" // Constants #define LINELENGTH 1000 // Types typedef struct line { char *str; struct line *ptr; } LINE; // Globals LINE *first; LINE *current; // Function to read one line from a specified stream. Return value is // 1 if an EOF was encountered. Otherwise 0. int read_line(FILE *stream, char line[LINELENGTH])// line在这里为一个字符数组 { if (fgets(line,LINELENGTH,stream)==NULL) return 1; //每次都读一行 line[strlen(line)-1] = '\0'; // Erase the terminating NEWLINE return 0; } // Function to read in the whole file into a linked-list buffer, so that we // can do several passes on it, as required to read the GML format // efficiently int fill_buffer(FILE *stream) { int length; char line[LINELENGTH]; LINE *previous; //之前的指针 if (read_line(stream,line)!=0) { first = NULL; // Indicates empty buffer return 1; } length = strlen(line) + 1; first = malloc(sizeof(LINE));//first 为指向第一个节点的指针 first->str = malloc(length*sizeof(char)); strcpy(first->str,line); //用于完成将读到到line字符串赋值到 LINE的链表中。 previous = first; while (read_line(stream,line)==0) { //将GML文件的每一行存在以FIRST存放的链表中,而LINE结构体为链表的节点。 length = strlen(line) + 1; //而LINE结构体中的,str字符指针,用来连接读到到字符串,这里的加1是为了存放\0空字符。 previous->ptr = malloc(sizeof(LINE)); previous = previous->ptr; previous->str = malloc(length*sizeof(char)); strcpy(previous->str,line); } previous->ptr = NULL; // Indicates last line //将最后一个节点的ptr的指向为空,说明链表到了尾点 return 0; } // Function to free up the buffer again void free_buffer() { LINE *thisptr; LINE *nextptr; thisptr = first; while (thisptr!=NULL) { nextptr = thisptr->ptr; free(thisptr->str); //释放thisptr所指向的字符串 free(thisptr); //释放LINE节点 thisptr = nextptr; //将thisptr释放后,thisptr向前移 } } // Function to reset to the start of the buffer again // 让目前指针,指向开始的位置 void reset_buffer() { current = first; } // Function to get the next line in the buffer. Returns 0 if there was // a line or 1 if we've reached the end of the buffer. int next_line(char line[LINELENGTH]) { if (current==NULL) return 1; //current指针,指向当前的LINE节点,然后LINE节点的str指针所指向的字符串赋值到line的字符数组中 strcpy(line,current->str); current = current->ptr; return 0; } // Function to establish whether the network read from a given stream is //判断这个网络是有向图还是无向图 // directed or not. Returns 1 for a directed network, and 0 otherwise. If // the GML file contains no "directed" line then the graph is assumed to be // undirected, which is the GML default behavior. //如果GML图中,不包含有向的直线,那么我们认为其为无向图。 int is_directed() //无向图同时也是GML默认的行为。 { int result=0; char *ptr; char line[LINELENGTH]; reset_buffer(); //通常和net_line函数一起使用,因为它重置了current指针,可以再net_line中使用。 while (next_line(line)==0) { ptr = strstr(line,"directed"); //strstr函数的作用,就是在line中查找derected这个字符串第一次出现的位置。 if (ptr==NULL) continue; sscanf(ptr,"directed %i",&result);//以ptr所指向的字符串,作为sscanf语句的输入 break; //并将其得到的数字按照十进制存储在result变量中 } return result; //只要是有向图,其directed后面一定会有数据的,这样result值不会为0,用以判断。 } // Function to count the vertices in a GML file. Returns number of vertices. //怎么来查找node节点呢?首先找到"node ["标志,然后在同一行里面没有"label"标志,则将node节点的数目加1 int count_vertices() { int result=0; char *ptr; char line[LINELENGTH]; reset_buffer(); //这样也是重置current指针,用来计算节点的数目 while (next_line(line)==0) { // next_line成功的时候返回的是0值。将LINE类型,名为current指针所指向节点的str返回所指向的那一行数据 ptr = strstr(line,"node ["); //其中strstr函数是很有用的,相当于用来匹配。 if (ptr!=NULL) { ptr = strstr(line,"label");//这个不太理解,其实所看到的gml格式的文件,不像是用txt格式打开的样子。但是从格式上看好像不会出现那个样子 if (ptr==NULL) result++; //如果找不到相应的字符串,则将指针置空,但是也不能计算节点的数目 } } return result; } // Function to compare the IDs of two vertices int cmpid(VERTEX *v1p, VERTEX *v2p) { if (v1p->id>v2p->id) return 1; //比较两个节点的id,大于的话返回1,小于的话返回-1. if (v1p->id<v2p->id) return -1; return 0; } // Function to allocate space for a network structure stored in a GML file // and determine the parameters (id, label) of each of the vertices. void create_network(NETWORK *network) { int i; int length; char *ptr; char *start,*stop; char line[LINELENGTH]; char label[LINELENGTH]; // Determine whether the network is directed network->directed = is_directed(); // Count the vertices network->nvertices = count_vertices(); // Make space for the vertices network->vertex = calloc(network->nvertices,sizeof(VERTEX));// 运用calloc函数一下分配多个节点的空间,将所有的节点穿成链表。 //并将首地址 赋值给network的vertex指针。相当于构建了一个数组 // Go through the file reading the details of each vertex one by one reset_buffer(); //这个函数调用的好及时啊,重新设置current指针。使其与first相同,共同指向第一个LINE节点 for (i=0; i<network->nvertices; i++) { // Skip to next "node" entry do { next_line(line); } while (strstr(line,"node")==NULL); //先读,然后判断。当寻到"node"时,说明这一行描述的为node节点。 // Read in the details of this vertex do { //从上面可以看出,gml格式的话, // Look for ID //查询ID ptr = strstr(line,"id"); if (ptr!=NULL) sscanf(ptr,"id %i",&network->vertex[i].id); // Look for label //查询label ptr = (strstr(line,"label")); //这个循环写的好啊!充分体现了当node、id、label三者在不同的行的情况下如何处理。 if (ptr!=NULL) { //标记处!!!和最外层的括号相对应。 start = strchr(line,'"'); //在line中,strchr(s,c).在字符串s中,首次出现字符c的位置。 if (start==NULL) { //""的意思是出现"的地方,因为不能确定label是否是字符串,存在的话返回指向c的指针,不存在的话返回NULL sscanf(ptr,"label %s",&label); } else { stop = strchr(++start,'"');//这样的话相对于start=strstr(line,"label")来说,只是起始位置发生了变化,原先为line字符数组的起始位置 if (stop==NULL) length = strlen(line) - (start-line); //现在为label标签项下的字符串的第一个字符。 else length = stop - start; //在这里做了一个判断,看一看其标签是否为一字符串,同时具有" ". strncpy(label,start,length); label[length] = '\0'; network->vertex[i].label = malloc((length+1)*sizeof(char));//当label可以给length个元素赋值的时候,其元素的个数为length+1 strcpy(network->vertex[i].label,label);//区分,一个label是属于自定义的,而另一个则属于vertex } }//和标记处的if相对应。 // If we see a closing square bracket we are done if (strstr(line,"]")!=NULL) break; //这样的话已经找到结束的标志,结束就好了,同时也可以看到]应该和node[ 并不在一行中。 } while (next_line(line)==0);//如果说ptr=NULL的话,那么就直接再读下一行 } // Sort the vertices in increasing order of their IDs so we can find them // quickly later //对节点进行排序,为后面的节点查找做准备。 qsort(network->vertex,network->nvertices,sizeof(VERTEX),(void*)cmpid); } // Function to find a vertex with a specified ID using binary search.//使用二分查找,来查找给予特定ID的节点。 // Returns the element in the vertex[] array holding the vertex in question, // or -1 if no vertex was found. //找到的话返回这个节点,找不到的话就返回-1,二分查找的程序以后很可能会遇到。 int find_vertex(int id, NETWORK *network) { int top,bottom,split; int idsplit; top = network->nvertices; if (top<1) return -1; bottom = 0; split = top/2; //节点的分割点,因为这个时候,链表已经按照节点的ID的大小已经排好序了,并且按照的是从小到大的顺序。 do { idsplit = network->vertex[split].id;//split链表处所对应的ID为多少 if (id>idsplit) { bottom = split + 1; split = (top+bottom)/2;//在这个时候top的值为发生变化,只是重新寻找split的位置。 } else if (id<idsplit) { top = split; split = (top+bottom)/2;//其值要么大,要么小,要么就只有等于。 } else return split; } while (top>bottom); return -1; } // Function to determine the degrees of all the vertices by going through // the edge data void get_degrees(NETWORK *network)//这里计算点的度数并没有计算权值 { int s,t; // 这里的st,表示的source节点,与target目标节点。 int vs,vt; char *ptr; char line[LINELENGTH]; reset_buffer(); //重置current指针。 while (next_line(line)==0) { // Find the next edge entry ptr = strstr(line,"edge"); if (ptr==NULL) continue; //直到遇到"edge"的字符串为止。 // Read the source and target of the edge s = t = -1; //此时的请求,说明已经找到edge所在的行。 do { ptr = strstr(line,"source"); if (ptr!=NULL) sscanf(ptr,"source %i",&s); ptr = strstr(line,"target"); if (ptr!=NULL) sscanf(ptr,"target %i",&t); // If we see a closing square bracket we are done if (strstr(line,"]")!=NULL) break; } while (next_line(line)==0); //这个的表示方式,和之前将节点的ID和节点的label基本上就是相同的,并充分考虑了第一次并未遇到source的情况 // Increment the degrees of the appropriate vertex or vertices if ((s>=0)&&(t>=0)) { //在网络中,找到相应的ID所对应的VERTEX节点。并改变vertex节点的度数。 vs = find_vertex(s,network); network->vertex[vs].degree++; if (network->directed==0) { //如果这个网络为无向图,则增加目标节点的度数。 vt = find_vertex(t,network); network->vertex[vt].degree++; } }//对应前面的两个if语句 }//对应的是外层的while循环 return; } // Function to read in the edges void read_edges(NETWORK *network) { int i; int s,t; //对应gml文件中的source节点,和target节点 int vs,vt; //对应于NETWORK网络中的源节点与目标节点。 int *count; double w;// 对应于权值,这里的类型设置的也不错 char *ptr; char line[LINELENGTH]; // Malloc space for the edges and temporary space for the edge counts 边计数 // at each vertex for (i=0; i<network->nvertices; i++) { network->vertex[i].edge = malloc(network->vertex[i].degree*sizeof(EDGE));//分配用于存储节点i所对应的边EDGE结构的题的空间的集合。 } count = calloc(network->nvertices,sizeof(int));//分配n个int存储空间。并将分配的地址复制给count指针变量 //对应每一个节点所连接的边的数目,比如说count[12]=3;表示的是节点12有三条边相连。 // Read in the data //这个值应该和节点的度数一直啊 reset_buffer();//和前面的作用一样 while (next_line(line)==0) { // Find the next edge entry ptr = strstr(line,"edge"); if (ptr==NULL) continue; // Read the source and target of the edge and the edge weight s = t = -1; w = 1.0; do { ptr = strstr(line,"source"); //这里很简单的将source、target、value的值分别存于s,t,w这三个变量中。 if (ptr!=NULL) sscanf(ptr,"source %i",&s); ptr = strstr(line,"target"); if (ptr!=NULL) sscanf(ptr,"target %i",&t); ptr = strstr(line,"value"); if (ptr!=NULL) sscanf(ptr,"value %lf",&w); // If we see a closing square bracket we are done if (strstr(line,"]")!=NULL) break; } while (next_line(line)==0); // Add these edges to the appropriate vertices if ((s>=0)&&(t>=0)) { //在gml文件中,找到source节点与target节点,并找到两个节点之间多对应的权值。 vs = find_vertex(s,network); vt = find_vertex(t,network); network->vertex[vs].edge[count[vs]].target = vt;//刚开始式子有点长,看起来很复杂。在确定vetex之后,对target进行复制。 network->vertex[vs].edge[count[vs]].weight = w;//count[vs]并未有值啊?count[vs]为一个变量,起始值为0.edge[count[vs]]也只是一个EDGE的结构体 count[vs]++; //count[vs]的值在发生变化,最后记录的是某一个节点多对应的边的数目。 if (network->directed==0) { //并将这些权值赋予NETWORK中的 network->vertex[vt].edge[count[vt]].target = vs; network->vertex[vt].edge[count[vt]].weight = w; count[vt]++; } } } free(count); return; } // Function to read a complete network int read_network(NETWORK *network, FILE *stream) { fill_buffer(stream); create_network(network); get_degrees(network); read_edges(network); free_buffer(); return 0; } // Function to free the memory used by a network again void free_network(NETWORK *network) { int i; for (i=0; i<network->nvertices; i++) { //在释放的时候,先释放边,在释放标签,最后释放节点。 free(network->vertex[i].edge); free(network->vertex[i].label); } free(network->vertex); }
相关文章推荐
- gml文件格式解析程序之头文件
- 小程序爆破之旅---分析微信源码来解析微信小程序文件格式
- wav文件格式分析详解和解析代码
- wav文件格式分析详解和解析代码
- FIT文件格式解析及MATLAB读取程序
- IOS 简单的本地json格式文件解析的实例详解
- 在Go语言程序中使用gojson来解析JSON格式文件
- wav文件格式分析详解和解析代码
- FIT文件格式解析及MATLAB读取程序
- wav文件格式分析详解和解析代码
- 怎样在Android中解析doc、docx、xls、xlsx格式文件?
- 未能加载文件或程序集''file:///D:/Program Files (x86)/ArcGIS/DeveloperKit10.0/DotNet/ESRI.ArcGIS.ADF.Local.dll'' 或它的某一个依赖项。试图加载格式不正确的程序。
- ELF格式文件详解
- ELF格式文件符号表全解析及readelf命令使用方法
- mp4文件格式解析,为demux准备的代码
- 3D中的OBJ文件格式详解
- DexFile文件格式解析
- mp4文件格式解析(四)
- Android Dex文件格式解析
- net控件中数据导到Excel的格式 首先,我们了解一下excel从web页面上导出的原理。当我们把这些数据发送到客户端时,我们想让客户端程序(浏览器)以excel的格式读取它,所以把mime类型设为:application/vnd.ms-excel,当excel读取文件时会以每个cell的格式呈现数据,如果cell没有规定的格式,则excel会以默认的格式去呈现该cell的数据。这样就给我们提供了自定义数据格式的空间,当然我们必须使用excel支持的格式。下面就列出常用的一些格式: 1) 文本