Criando o projeto
Vamos criar um projeto em C++ que utiliza o conceito de grafo orientado. Um nó pode se conectar por meio de arestas a outros nós, formando um grafo. Dessa forma, precisamos representar os nós, as arestas e o grafo em si.
Projeto
Seção intitulada “Projeto”Acesse a pasta ~/dev/c_cpp_projects
que criamos anteriormente.
Dentro dela, crie um diretório chamado oriented_graph
.
Acesse-o e abra nele o Visual Studio Code.
mkdir -p ~/dev/c_cpp_projectscd ~/dev/c_cpp_projectsmkdir -p oriented_graphcd oriented_graphcode .
Dentro do diretório oriented_graph
, crie um arquivo main.cpp
e três pastas: node
, edge
e graph
.
Cada pasta deve conter um arquivo .cpp
e um arquivo .hpp
com o mesmo nome da pasta.
touch main.cpp .clang-tidy .clang-formatmkdir -p node edge graphtouch node/node.cpp node/node.hpp edge/edge.cpp edge/edge.hpp graph/graph.cpp graph/graph.hpp
Copie o código de cada arquivo a seguir para o seu projeto.
#include <iostream>
#include "graph/graph.hpp"
using namespace std;
int main() { Graph graph;
graph.addNode(1, 10); graph.addNode(2, 20); graph.addNode(3, 30); graph.addNode(4, 40); graph.addNode(5, 50);
graph.addEdge(1, 2, 10); graph.addEdge(1, 3, 20); graph.addEdge(2, 3, 30); graph.addEdge(3, 4, 40); graph.addEdge(4, 5, 50);
vector<unsigned long> connected_nodes = graph.depthFirstSearch(1);
for (unsigned long label : connected_nodes) { cout << label << " "; }
cout << endl;
return 0;}
#ifndef __NODE_HPP__#define __NODE_HPP__
class Node { private: unsigned long id; unsigned long label; int data;
public: Node(unsigned long id, unsigned long label, int data);
~Node() {}
unsigned long getId() const; unsigned long getLabel() const; int getData() const;
void setData(int data);};
#endif // __NODE_HPP__
#include "node.hpp"
Node::Node(unsigned long id, unsigned long label, int data) { this->id = id; this->label = label; this->data = data;}
unsigned long Node::getId() const { return this->id;}
unsigned long Node::getLabel() const { return this->label;}
int Node::getData() const { return this->data;}
void Node::setData(int data) { this->data = data;}
#ifndef __EDGE_HPP__#define __EDGE_HPP__
#include "../node/node.hpp"
class Edge { private: unsigned long id; Node *source; Node *target; int weight;
public: Edge(unsigned long id, Node *source, Node *target, int weight);
~Edge() {}
unsigned long getId() const; Node *getSource() const; Node *getTarget() const; int getWeight() const;
void setWeight(int weight);};
#endif // __EDGE_HPP__
#include "edge.hpp"
Edge::Edge(unsigned long id, Node *source, Node *target, int weight) { this->id = id; this->source = source; this->target = target; this->weight = weight;}
unsigned long Edge::getId() const { return this->id;}
Node *Edge::getSource() const { return this->source;}
Node *Edge::getTarget() const { return this->target;}
int Edge::getWeight() const { return this->weight;}
void Edge::setWeight(int weight) { this->weight = weight;}
#ifndef __GRAPH_HPP__#define __GRAPH_HPP__
#include <optional>#include <vector>
#include "../edge/edge.hpp"#include "../node/node.hpp"
using namespace std;
class Graph { private: unsigned long last_node_id; vector<Node *> nodes; unsigned long last_edge_id; vector<Edge *> edges;
Node *getNodeByLabel(unsigned long label) const;
void clearNodes(); void clearEdges();
public: Graph(); ~Graph();
optional<int> getNodeData(unsigned long label) const;
void addNode(unsigned long label, int data); void addEdge(unsigned long source_label, unsigned long target_label, int weight);
vector<unsigned long> depthFirstSearch(unsigned long start_label) const;};
#endif // __GRAPH_HPP__
#include "graph.hpp"
#include <algorithm>
Graph::Graph() { this->last_node_id = 0; this->last_edge_id = 0;}
Graph::~Graph() { this->clearNodes(); this->clearEdges();}
Node *Graph::getNodeByLabel(unsigned long label) const { for (Node *node : this->nodes) { if (node->getLabel() == label) { return node; } }
return nullptr;}
void Graph::clearNodes() { for (Node *node : this->nodes) { delete node; }
this->nodes.clear();}
void Graph::clearEdges() { for (Edge *edge : this->edges) { delete edge; }
this->edges.clear();}
optional<int> Graph::getNodeData(unsigned long label) const { Node *node = this->getNodeByLabel(label);
if (node == nullptr) { return nullopt; }
return node->getData();}
void Graph::addNode(unsigned long label, int data) { Node *node = new Node(this->last_node_id++, label, data); this->nodes.push_back(node);}
void Graph::addEdge(unsigned long source_label, unsigned long target_label, int weight) { Node *source = this->getNodeByLabel(source_label); Node *target = this->getNodeByLabel(target_label);
if (source == nullptr || target == nullptr) { return; }
Edge *edge = new Edge(this->last_edge_id++, source, target, weight); this->edges.push_back(edge);}
vector<unsigned long> Graph::depthFirstSearch(unsigned long start_label) const { vector<unsigned long> visited; vector<unsigned long> stack;
stack.push_back(start_label);
while (!stack.empty()) { unsigned long current_label = stack.back(); stack.pop_back();
if (find(visited.begin(), visited.end(), current_label) != visited.end()) { continue; }
visited.push_back(current_label);
Node *current_node = this->getNodeByLabel(current_label);
for (Edge *edge : this->edges) { if (edge->getSource() == current_node) { stack.push_back(edge->getTarget()->getLabel()); } } }
return visited;}
Também crie o arquivo .clang-tidy
na raiz do projeto e o preencha com o snippet clang-tidy
.
Igualmente, crie o arquivo .clang-format
e o preencha com o snippet clang-format
.
Da mesma forma como fizemos anteriormente, vamos inicializar o repositório Git e criar um arquivo .gitignore
para que arquivos de compilação não sejam versionados.
git initecho -e "## Build\n.cache/\nbuild/" >> .gitignoregit add .git commit -m "Initialize project"
Compilação
Seção intitulada “Compilação”Assim como antes, você pode compilar esse projeto diretamente pelo clang++
ou utilizando os arquivos tasks.json
e launch.json
do Visual Studio Code.
O comando de compilação é o seguinte.
mkdir -p buildclang++ main.cpp node/node.cpp edge/edge.cpp graph/graph.cpp -I node -I edge -I graph -o build/oriented_graph
Ao executar o programa, você verá a seguinte saída.
./build/oriented_graph# 1 3 4 5 2
Ela representa a ordem de visitação dos nós do grafo em uma busca em profundidade iniciando pelo nó 1.