BFS与Dijkstra的运行时间,价值观没有意义

时间:2016-05-10 04:16:10

标签: c++ list matrix dijkstra breadth-first-search

我在邻接列表和邻接矩阵上对Dijkstra和BFS进行了比较。我将所有四种变体作为最短路径算法进行测试,并将其运行时间计算在从稀疏到密集的未加权图形上。

我的理解是邻接列表应该在稀疏图上表现更好(即,具有更快的时钟时间),并且随着图变得更密集,矩阵最终将变得更快。然而,当我运行我的代码时,矩阵总是超出列表,我不能为我的生活理解为什么。任何见解都会令人难以置信。

// main.cpp中

#include <iostream>
#include <fstream>
#include "Graph.h"
#include <sys/time.h>
#include <ctime>
#include <chrono>


using namespace std;

int main(int argc, char *argv[]) {
    //struct timeval begin, finish;

    int numVertices = 10;

    //Calculate the maximum number of edges that can exist in an undirected graph
    int maxNumEdges = (numVertices*(numVertices-1))/2;
    cout << "maxNumEdges" << maxNumEdges << endl;

    //Run all the algorithms with increasing number of edges
    for(int i = 0; i < maxNumEdges; i++) {
        int numEdges = i;
        Graph g(numVertices);
        cout <<  "Number of edges: " << numEdges << endl;

        g.generate(numEdges);
        int destination = g.getDestination();

        std::chrono::steady_clock::time_point begin1 = std::chrono::steady_clock::now();
        g.adjListBFS(0, destination);
        std::chrono::steady_clock::time_point end1= std::chrono::steady_clock::now();

        std::chrono::steady_clock::time_point begin2 = std::chrono::steady_clock::now();
        g.matrixBFS(0, destination);
        std::chrono::steady_clock::time_point end2= std::chrono::steady_clock::now();


        std::chrono::steady_clock::time_point begin3 = std::chrono::steady_clock::now();
        g.dijkstraList(0, destination);
        std::chrono::steady_clock::time_point end3= std::chrono::steady_clock::now();


        std::chrono::steady_clock::time_point begin4 = std::chrono::steady_clock::now();
        g.dijkstraMatrix(0, destination);
        std::chrono::steady_clock::time_point end4= std::chrono::steady_clock::now();
        //cout << endl;

        cout << "BfSList Time: " << std::chrono::duration_cast<std::chrono::microseconds>(end1 - begin1).count() << " ";
        cout << "BFS Matrix Time: " << std::chrono::duration_cast<std::chrono::microseconds>(end2 - begin2).count() << " ";
        cout << "DijList Time: " << std::chrono::duration_cast<std::chrono::microseconds>(end3 - begin3).count() << " ";
        cout << "DijMatrix Time: " << std::chrono::duration_cast<std::chrono::microseconds>(end4 - begin4).count() << " ";
        cout << endl;

        //break;

    }

}

// Graph.cpp

#include "Graph.h"
#include <iostream>
#include <fstream>
#include <string>
#include <queue>
#include <stdlib.h>
#include <vector>
#include <list> 
#include <limits>
#include <algorithm>

using namespace std;

//Constructor
Graph::Graph(int numV) {
    numVertices = numV;

    //intialize vertex array
    vertexArray = new int[numVertices];
    //Initialize adjacency list
    adjList = new list<int>[numVertices];
    //Initialize matrix
    matrix = new int*[numVertices];
    for(int i = 0; i < numVertices; i++) {
        matrix[i] = new int[numVertices];
    }
    for(int i = 0; i < numVertices; i++) {
        for(int j = 0; j < numVertices; j++) {
        matrix[i][j] = 0;   
        }
    }
}


//Generate a random graph
void Graph::generate(int numEdges) {
    srand(time(NULL));
    int currentEdges = 0;
    int v1 = rand() % numVertices-1;

    //Pick destination vertex. If 0 randomly generated, just add 1 to it
    int dest = rand() % numVertices;
    if (dest != 0) {
        destination = dest;
    } else {
        destination = 1;
    }

    while(currentEdges < numEdges) {
        //cout << "stuck in generate while" << endl;
        for(int i = 0; i < numVertices; i++) {
            //cout << "Stuck in first for loop" << endl;
            v1 = rand() % numVertices;
            if (edgeExists(i, v1) == true || i == v1) {
                //cout << "hit if" << endl;
                //i--;
            } else {
                adjList[i].push_back(v1);
                adjList[v1].push_back(i);
                matrix[i][v1] == 1;
                matrix[v1][i] == 1;
                currentEdges++;
                //cout << "Hit else" << endl;
            //cout << "Added " << i << " to " << v1 << " list" << endl;
            //cout << "Added " << v1 << " to " << i << " list" << endl;
            }
        }
    }
}


//Checking to be sure edge is not added twice
bool Graph::edgeExists(int v1, int v2) {
    bool alreadyAdded = false;
    for(list<int>::iterator i = adjList[v1].begin(); i != adjList[v1].end(); ++i) {
        //cout << "(*i): " << (*i) << " v2: " << v2 << endl;
        if(*i == v2) {
            alreadyAdded = true;
        } 
    }
    return alreadyAdded;
}

//In list already - make sure correct number of vertices are created
bool Graph::inList(int v1) {
    bool check = false;
    for(vector<int>::iterator i = vectorVertex.begin(); i != vectorVertex.end(); ++i) {
        if((*i) == v1) {
            check = true;
        }   
    }
    return check;
}

//================================================BFS with adjacency list====================================================
void Graph::adjListBFS(int s, int e){ 
    int nodesVisited = 0;
    bool foundDest = false;
    bool *visited = new bool[numVertices];
    int *previous = new int[numVertices];
    int start = s;
    int dest = e;

    //Initialize vertices to 'not visited'
    for(int i = 0; i < numVertices; i++) {
        visited[i] = false;
    }

    //Create a queue, push starting vertex on
    queue<int> Q;
    visited[s] = true;
    Q.push(s);
    //cout << "BFS complete traversal: ";

    while(!Q.empty() && foundDest == false) {
            s = Q.front();
            Q.pop();
        //  cout << s << " -> ";
            nodesVisited++;
            for(list<int>::iterator i = adjList[s].begin(); i != adjList[s].end(); ++i) {
                if(!visited[*i]) {
                    visited[(*i)] = true;
                    Q.push(*i);
                    previous[(*i)] = s;

                    if((*i) == e) {
                        foundDest = true;
                        //cout << e << endl;
                        break;
                    }
                } 
            }
     }
    vector<int> pathVector;
    //bool check = false;
    //printPath(previous, e);
    //cout << "Backwards path: " << e << " <- ";
   /*   for(int i = 0; i < numVertices; i++) {
        cout << previous[e] << " <- ";
        if(previous[e] == start) {
            break;
        } else {
            e = previous[e];
        }
    }*/

    /*pathVector.push_back(start);
    for(vector<int>::iterator i = pathVector.end(); i != pathVector.begin(); --i) {
        cout << pathVector.at(*i) << " -> ->  " ;
    }*/

    //cout << endl;
            //  cout << "stuck in BFS adjlist" << endl;

}

//====================================================BFS with Matrix===========================================================


void Graph::matrixBFS(int s, int e){ 
    bool foundDest = false;
    bool *visited = new bool[numVertices];

    //Initialize vertices to 'not visited'
    for(int i = 0; i < numVertices; i++) {
        visited[i] = false;
    }

    //Create a queue, push starting vertex on
    queue<int> Q;
    visited[s] = true;
    Q.push(s);

    //While there are still vertices to process
     while(!Q.empty() && foundDest == false) {
            s = Q.front();
            Q.pop();
            //cout << s << " -> ";

            for(int i = 0; i < numVertices; i++) {
                if(matrix[i][s] == 1 && visited[i] == false) {
                    visited[i] = true;
                    Q.push(i);
                } 
                if(s == e) {
                foundDest = true;
                break;
            }
            }
     }
    //cout << endl;


}

//For reconstructing the path 
void Graph::printPath(int parent[], int j) {
    if (parent[j] == -1) {
        return;
    }

    printPath(parent, parent[j]);
    //cout << j << "->" << endl;
    //cout << " ";
}



//======================================================Dijkstra Matrix============================================================
void Graph::dijkstraMatrix(int s, int e) {
    bool foundDest = false;
    int infinity = numeric_limits<int>::max();
    int distance[numVertices];
    bool visited[numVertices];
    int parent[numVertices];

    for(int i = 0; i < numVertices; i++) {
        parent[i] = -1;
        distance[i] = infinity;
        visited[i] = false;
    }

    //Distance from starting vertex to itself is 0
    distance[s] = 0;

    //Create a queue, push first element on
    queue<int> dijQueue;
    dijQueue.push(s);

    while(!dijQueue.empty() && foundDest == false) {
        int current = dijQueue.front();
        dijQueue.pop();
        visited[current] = true;

            for (int i = 0; i < numVertices; i++) {
                if(!visited[i] && matrix[current][i] && distance[current]+matrix[s][i] < distance[i]) {
                    parent[i] = current;
                    distance[i] = distance[current] + 1;
                    if(s == e) {
                        foundDest = true;
                        break;
                    }
                    dijQueue.push(i);
                }
            }   
    }

/*  int startVertex = 0;
    //cout << "Path" << " " << "Vertex" << " " << "Distance" << endl;
    for (int i= 1; i < numVertices; i++) {
        printPath(parent, i);
        //cout << "    " << startVertex << "-->" << i << "   " << "        " << endl;   
    }*/
                    //  cout << "stuck in Dijkstra Matrix" << endl;

}

//==================================================Dijkstra Adjacency List============================================================
void Graph::dijkstraList(int s, int e) {
    bool foundDest = false;
    int infinity = numeric_limits<int>::max();
    int distance[numVertices];
    bool visited[numVertices];
    int parent[numVertices];

    //Initialize
    for(int i = 0; i < numVertices; i++) {
        parent[i] = -1;
        distance[i] = infinity;
        visited[i] = false;
    }

    //Distance from starting vertex to itself is 0
    distance[s] = 0;

    //Create a queue, push first element on
    queue<int> dijQueue;
    dijQueue.push(s);

    //While there are still vertexes to process
    while(!dijQueue.empty() && foundDest == false) {
        int current = dijQueue.front();
        dijQueue.pop();
        visited[current] = true;

            //cout << "current: " << current << endl;

        for(list<int>::iterator i = adjList[current].begin(); i != adjList[current].end(); ++i) {

            if(!visited[*i] && (distance[current]+1) < distance[*i]) {
                parent[*i] = current;
                distance[*i] = distance[current] + 1;
                if(s == e) {
                    foundDest = true;
                    break;
                }
                dijQueue.push(*i);
            }
        }
    }

    //Print results
    int startVertex = 0;
    //cout << startVertex << " ";
    //printPath(parent, e);
                            //cout << "stuck in Dijkstra List" << endl;


}

//Returns the "ending" vertex that was randomly generated
int Graph::getDestination() {
    return destination;
}

// Graph.h

#ifndef GRAPH_H_
#define GRAPH_H_
#include <iostream>
#include <queue>
#include <vector>
#include <list>
#include <fstream>

using namespace std;

class Graph {

    private:
        int numVertices;
        list<int> *adjList;
        int *vertexArray;
        int **matrix;
        vector<int> vectorVertex;


    public: 
        int destination;
        int currentNumVertices;
        Graph(int numV);
        void generate(int numEdges);
        int getDestination();

        bool inList(int v1);
        bool edgeExists(int v1, int v2);
        void adjListBFS(int s, int e);
        void matrixBFS(int s, int e);
        void dijkstraMatrix(int s, int e);
        void dijkstraList(int s, int e);

        void printPath(int parent[], int j);

};

#endif

1 个答案:

答案 0 :(得分:0)

也许是因为你在这里进行比较而不是作业:

matrix[i][v1] == 1;
matrix[v1][i] == 1;

那应该是=而不是==