图的数据读取和广度优先搜索

  对于一个图或者网络 G = ( V , E ) \mathcal{G}=(V,E) G=(V,E)来说,其数据一般有两种表示方式,第一种是一个行数和列数均为 ∣ V ∣ |V| V的邻接矩阵,第二种是只记录连边信息的邻接表.如果网络的规模很大,那么邻接矩阵的数据空间需要 O ( ∣ V ∣ 2 ) O(|V|^2) O(V2)复杂度,所以是不现实的,这时一般采用邻接表的方式进行表示.在C/C++的数据结构中,先定义一个结构体数组表示所有的节点,然后定义每个节点的多条连边,连边信息以链表形式关联起来,从而形成邻接表.
  在网络上计算单源最短路径一般使用Dijkstra算法,时间复杂度为 O ( ∣ V ∣ 2 ) O(|V|^2) O(V2),还有一种经过堆优化的Dijkstra算法其复杂度可以降低一些.对于特殊情况的无权网络,Dijkstra算法可以等同于广度优先搜索BFS,其时间复杂度为 O ( ∣ V ∣ + ∣ E ∣ ) O(|V|+|E|) O(V+E).默认图的数据以txt格式保存,每行代表一个连边,其实节点和终止节点以空格符隔开,最后以C++实现图的数据读取和广度有限搜索,并将其封装为一个头文件Graph.h.

#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<string>
#include<string.h>
#include<queue>
#define MAX_LINE 16

using namespace std;

struct Edges{
    int vertexIndex;
    int distance;
    struct Edges *nextEdge;
};

struct Vertices{
    int name;
    Edges *firstEdge = NULL;
    Edges *tailEdge;
};

struct edgeList{
    int vertexFrom;
    int vertexTo;
    struct edgeList *next;
};

void readTxtFile(struct edgeList *head,char const *fileName,int &numVertices,int &numEdges);

class Graph{
public:
    int numVertices;
    int numEdges;
    Vertices *vertices;

    Graph(){/*无参构造函数*/
        this -> numVertices = -1;
        this -> numEdges = -1;
        this -> vertices = NULL;
    };

    void readGraph(char const *fileName);/*读取图网络数据文件*/

    void BFS(int vertexIndex,int *distList);/*图结构的广度优先搜索算法*/

    ~Graph();
};

Graph::~Graph(){/*析构函数*/
    int deleteNumEdges = 0;
    for(int i = 0;i < this -> numVertices;i++){
        while(this -> vertices[i].firstEdge != NULL){
            this -> vertices[i].tailEdge = this -> vertices[i].firstEdge;
            this -> vertices[i].firstEdge = this -> vertices[i].tailEdge -> nextEdge;
            this -> vertices[i].tailEdge = NULL;
            delete(this -> vertices[i].tailEdge);
            deleteNumEdges++;
        }
        this -> vertices[i].tailEdge = NULL;
    }
    delete[] this -> vertices;
    this -> vertices = NULL;
    cout<<"删除的连边数为:"<<deleteNumEdges<<endl;
}

void Graph::BFS(int vertexIndex,int *distList){
    bool *visitedList = new bool[this -> numVertices];
    struct Edges *p;/*创建指针*/
    for(int i = 0;i < this -> numVertices;i++){
        visitedList[i] = false;
    }
    visitedList[vertexIndex] = true;
    distList[vertexIndex] = 0;
    queue<int> *q = new queue<int>;/*用STL队列实现,#include<queue>*/
    q -> push(vertexIndex);/*入队*/
    while(!q -> empty()){/*队列非空时执行循环*/
        int u = q -> front();/*取队头元素*/
        p = this -> vertices[u].firstEdge;
        while(p != NULL){
            if(!visitedList[p -> vertexIndex]){
                q -> push(p -> vertexIndex);/*入队*/
                distList[p -> vertexIndex] = distList[u] + 1;/*路径长度+1*/
                visitedList[p -> vertexIndex] = true;/*置为已考察*/
            }
            p = p -> nextEdge;
        }
        q -> pop();/*出队*/
    }
    delete[] visitedList;
}

void Graph::readGraph(char const *fileName){
    /*--------------------读取网络数据--------------------*/
    struct edgeList *head = new edgeList;/*创建头节点*/
    readTxtFile(head,fileName,this -> numVertices,this -> numEdges);
    /*--------------------构建邻接表--------------------*/
    struct edgeList *p = head -> next;
    struct Edges *edges;
    this -> vertices = new Vertices[this -> numVertices];
    for(int i = 0;i < this -> numEdges;i++){/*遍历链表并打印数据*/
        edges = new Edges;
        edges -> vertexIndex = p -> vertexTo;
        edges -> nextEdge = NULL;
        if(this -> vertices[p -> vertexFrom].firstEdge == NULL){
            this -> vertices[p -> vertexFrom].firstEdge = edges;
            this -> vertices[p -> vertexFrom].tailEdge = edges;
        }
        else{
            this -> vertices[p -> vertexFrom].tailEdge -> nextEdge = edges;
            this -> vertices[p -> vertexFrom].tailEdge = edges;
        }
        p = p -> next;
    }
    /*内存释放*/
    while(head != NULL){/*删除链表*/
        p = head;
        head = p -> next;
        delete(p);
    }
    head = NULL;
    p = NULL;
    //edges = NULL;
}

void readTxtFile(struct edgeList *head,char const *fileName,int &numVertices,int &numEdges){
    char buf[MAX_LINE];/*缓冲区*/
    FILE *fid;/*文件指针*/
    int len;/*行字符个数*/
    int minVertexNum = 2;/*最小的节点标号*/
    int maxVertexNum = 0;/*最大的节点标号*/
    int vertexFrom;/*起始节点*/
    int vertexTo;/*终止节点*/
    char *buff;/*复制字符串用于分割*/
    char *strOfInt;/*复制分割后的字符串*/
    struct edgeList *p1 = NULL;/*开辟并保存新节点*/
    bool isDirected = false;
    struct edgeList *p2 = head;/*保存链表最后一个节点*/
    head -> vertexFrom = 0;
    head -> vertexTo = 1492;
    if((fid = fopen(fileName,"r")) == NULL){
        perror("fail to read");
        exit(1);
    }
    numEdges = 0;/*连边总数赋初值*/
    while(fgets(buf,MAX_LINE,fid) != NULL){
        buff = buf;
        strOfInt = strsep(&buff, " "); 
        vertexFrom = atoi(strOfInt);
        strOfInt = strsep(&buff, " ");
        vertexTo = atoi(strOfInt);
        if(minVertexNum > vertexFrom){
            minVertexNum = vertexFrom;
        }
        if(minVertexNum > vertexTo){
            minVertexNum = vertexTo;
        }
        if(maxVertexNum < vertexFrom){
            maxVertexNum = vertexFrom;
        }
        if(maxVertexNum < vertexTo){
            maxVertexNum = vertexTo;
        }
        strOfInt = strsep(&buff, " ");
        /*将数据写到链表当中存储*/
        p1 = new edgeList;
        p1 -> vertexFrom = vertexFrom;
        p1 -> vertexTo = vertexTo;
        p2 -> next = p1;
        p2 = p1;
        if(!isDirected){
            p1 = new edgeList;
            p1 -> vertexFrom = vertexTo;
            p1 -> vertexTo = vertexFrom;
            p2 -> next = p1;
            p2 = p1;
            numEdges++;
        }
        numEdges++;/*文件数据的总行数,网络边总数*/
    }
    if(minVertexNum != 0){/*保证节点编号从零开始*/
        p2 = head;
        while(p2 != NULL){
            p2 -> vertexFrom = p2 -> vertexFrom - minVertexNum;
            p2 -> vertexTo = p2 -> vertexTo - minVertexNum;
            p2 = p2 -> next;
        }
    }
    free(buff);/*释放指针内存*/
    buff = NULL;/*将指针置为空*/
    p2 -> next = NULL;
    int isClosed = fclose(fid);
    numVertices = maxVertexNum - minVertexNum + 1;/*网络节点的总数*/
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值