Graphes en Java

Graphes en Java

1. Vue d'ensemble

Dans ce didacticiel,we’ll understand the basic concepts of a graph as a data structure.

Nous allons également explorer sa mise en œuvre en Java ainsi que diverses opérations possibles sur un graphe. Nous discuterons également des bibliothèques Java offrant des implémentations de graphes.

2. Structure des données du graphique

Un graphique est undata structure for storing connected datacomme un réseau de personnes sur une plateforme de médias sociaux.

Un graphique est constitué de sommets et d'arêtes. A vertex represents the entity (par exemple, les gens) etan edge represents the relationship between entities (par exemple, les amitiés d'une personne).

Définissons un graphique simple pour mieux comprendre cela:

image image

Ici, nous avons défini un graphique simple avec cinq sommets et six arêtes. Les cercles sont des sommets représentant des personnes et les lignes reliant deux sommets sont des arêtes représentant des amis sur un portail en ligne.

Il existe quelques variantes de ce graphique simple en fonction des propriétés des arêtes. Passons brièvement en revue dans les sections suivantes.

Cependant, nous nous concentrerons uniquement sur le graphique simple présenté ici pour les exemples Java de ce didacticiel.

2.1. Graphique dirigé

Le graphique que nous avons défini jusqu'à présent a des arêtes sans aucune direction. Si cesedges feature a direction in them, le graphe résultant est appelé graphe orienté.

Un exemple de ceci peut être représentant qui envoie la demande d'ami dans une amitié sur le portail en ligne:

image image

Ici, nous pouvons voir que les bords ont une direction fixe. Les bords peuvent également être bidirectionnels.

2.2. Graphique pondéré

Encore une fois, notre graphique simple a des arêtes non biaisées ou non pondérées. Si à la place cesedges carry relative weight, ce graphique est connu sous le nom de graphique pondéré.

Un exemple d'application pratique de cela peut être de montrer à quel point une amitié est relativement ancienne sur le portail en ligne:

image image

Ici, nous pouvons voir que les arêtes sont associées à des poids. Cela donne une signification relative à ces bords.

3. Graph Representations

Un graphique peut être représenté sous différentes formes, telles que la matrice d'adjacence et la liste d'adjacence. Chacun a ses avantages et ses inconvénients dans une configuration différente.

Nous présenterons ces représentations graphiques dans cette section.

3.1. Matrice d'adjacence

Une matrice de contiguïté esta square matrix with dimensions equivalent to the number of vertices dans le graphique.

Les éléments de la matrice ont généralement les valeurs «0» ou «1». Une valeur de «1» indique une adjacence entre les sommets de la ligne et de la colonne et une valeur de «0» sinon.

Voyons à quoi ressemble la matrice de contiguïté pour notre graphique simple de la section précédente:

image image

Cette représentation est également assezeasier to implement and efficient to query. Cependant, c'estless efficient with respect to space occupied.

3.2. Liste d'adjacence

Une liste de contiguïté n'est rien d'autre quean array of lists. La taille du tableau est équivalente au nombre de sommets du graphique.

La liste à un index spécifique du tableau représente les sommets adjacents du sommet représenté par cet index de tableau.

Voyons à quoi ressemble la liste de contiguïté pour notre graphique simple de la section précédente:

image image

Cette représentation estcomparatively difficult to create and less efficient to query. Cependant, il propose desbetter space efficiency.

Nous utiliserons la liste de contiguïté pour représenter le graphique dans ce didacticiel.

4. Graphes en Java

Java n’a pas d’implémentation par défaut de la structure de données du graphique.

Cependant, nous pouvons implémenter le graphique à l'aide de Java Collections.

Commençons par définir un sommet:

class Vertex {
    String label;
    Vertex(String label) {
        this.label = label;
    }

    // equals and hashCode
}

La définition ci-dessus du sommet ne comporte qu'une étiquette mais cela peut représenter n'importe quelle entité possible commePerson ouCity.

Notez également quewe have to override the equals() and hashCode() methods as these are necessary to work with Java Collections.

Comme nous l'avons vu précédemment, un graphique n'est rien d'autre qu'un ensemble de sommets et d'arêtes pouvant être représentés sous forme de matrice d'adjacence ou de liste d'adjacence.

Voyons comment nous pouvons définir cela à l'aide d'une liste de contiguïté ici:

class Graph {
    private Map> adjVertices;

    // standard constructor, getters, setters
}

Comme nous pouvons le voir ici, la classeGraph utiliseMap des collections Java pour définir la liste de contiguïté.

Il existe plusieurs opérations possibles sur une structure de données de graphe, telles quecreating, updating or searching through the graph.

Nous allons passer en revue certaines des opérations les plus courantes et voir comment nous pouvons les implémenter en Java.

5. Opérations de mutation de graphe

Pour commencer, nous allons définir quelques méthodes pour muter la structure des données du graphique.

Définissons des méthodes pour ajouter et supprimer des sommets:

void addVertex(String label) {
    adjVertices.putIfAbsent(new Vertex(label), new ArrayList<>());
}

void removeVertex(String label) {
    Vertex v = new Vertex(label);
    adjVertices.values().stream().forEach(e -> e.remove(v));
    adjVertices.remove(new Vertex(label));
}

Ces méthodes ajoutent et suppriment simplement des éléments desvertices Set.

Maintenant, définissons également une méthode pour ajouter une arête:

void addEdge(String label1, String label2) {
    Vertex v1 = new Vertex(label1);
    Vertex v2 = new Vertex(label2);
    adjVertices.get(v1).add(v2);
    adjVertices.get(v2).add(v1);
}

Cette méthode crée un nouveauEdge et met à jour les sommets adjacentsMap.

De la même manière, nous définirons la méthoderemoveEdge():

void removeEdge(String label1, String label2) {
    Vertex v1 = new Vertex(label1);
    Vertex v2 = new Vertex(label2);
    List eV1 = adjVertices.get(v1);
    List eV2 = adjVertices.get(v2);
    if (eV1 != null)
        eV1.remove(v2);
    if (eV2 != null)
        eV2.remove(v1);
}

Voyons ensuite comment nous pouvons créer le graphique simple que nous avons dessiné précédemment en utilisant les méthodes que nous avons définies jusqu'à présent:

Graph createGraph() {
    Graph graph = new Graph();
    graph.addVertex("Bob");
    graph.addVertex("Alice");
    graph.addVertex("Mark");
    graph.addVertex("Rob");
    graph.addVertex("Maria");
    graph.addEdge("Bob", "Alice");
    graph.addEdge("Bob", "Rob");
    graph.addEdge("Alice", "Mark");
    graph.addEdge("Rob", "Mark");
    graph.addEdge("Alice", "Maria");
    graph.addEdge("Rob", "Maria");
    return graph;
}

Nous allons enfin définir une méthode pour obtenir les sommets adjacents d'un sommet particulier:

List getAdjVertices(String label) {
    return adjVertices.get(new Vertex(label));
}

6. Traverser un graphique

Maintenant que nous avons défini la structure et les fonctions de données de graphique pour la créer et la mettre à jour, nous pouvons définir des fonctions supplémentaires pour parcourir le graphique. Nous devons parcourir un graphique pour effectuer toute action significative, comme une recherche dans le graphique.

Il y atwo possible ways to traverse a graph, depth-first traversal and breadth-first traversal.

6.1. Traversal Profondeur-Premier

Une traversée en profondeur commence à un sommet racine arbitraire et àexplores vertices as deeper as possible along each branch before exploring vertices at the same level.

Définissons une méthode pour effectuer le parcours en profondeur d'abord:

Set depthFirstTraversal(Graph graph, String root) {
    Set visited = new LinkedHashSet();
    Stack stack = new Stack();
    stack.push(root);
    while (!stack.isEmpty()) {
        String vertex = stack.pop();
        if (!visited.contains(vertex)) {
            visited.add(vertex);
            for (Vertex v : graph.getAdjVertices(vertex)) {
                stack.push(v.label);
            }
        }
    }
    return visited;
}

Ici,we’re using a Stack to store the vertices that need to be traversed.

Exécutons ceci sur le graphique que nous avons créé dans la sous-section précédente:

assertEquals("[Bob, Rob, Maria, Alice, Mark]", depthFirstTraversal(graph, "Bob").toString());

Veuillez noter que nous utilisons ici le sommet "Bob" comme racine pour le parcours, mais cela peut être n'importe quel autre sommet.

6.2. Traversée en largeur d'abord

Comparativement, une traversée en largeur commence à un sommet racine arbitraire et àexplores all neighboring vertices at the same level before going deeper dans le graphe.

Définissons maintenant une méthode pour effectuer le parcours en largeur d'abord:

Set breadthFirstTraversal(Graph graph, String root) {
    Set visited = new LinkedHashSet();
    Queue queue = new LinkedList();
    queue.add(root);
    visited.add(root);
    while (!queue.isEmpty()) {
        String vertex = queue.poll();
        for (Vertex v : graph.getAdjVertices(vertex)) {
            if (!visited.contains(v.label)) {
                visited.add(v.label);
                queue.add(v.label);
            }
        }
    }
    return visited;
}

Notez qu'une traversée en largeur d'abordmakes use of Queue to store the vertices which need to be traversed.

Exécutons à nouveau ce parcours sur le même graphique:

assertEquals("[Bob, Alice, Rob, Mark, Maria]", breadthFirstTraversal(graph, "Bob").toString());

Encore une fois, le sommet de la racine qui est "Bob" peut également être n'importe quel autre sommet.

7. Bibliothèques Java pour les graphiques

Il n'est pas nécessaire de toujours implémenter le graphique à partir de zéro en Java. Il existe plusieurs bibliothèques open source et matures disponibles qui offrent des implémentations de graphes.

Dans les prochaines sous-sections, nous passerons en revue certaines de ces bibliothèques.

7.1. JGraphT

JGraphT est l'une des bibliothèques Java les plus populaires pour la structure de données de graphe. Il permet la création d'un graphe simple, d'un graphe orienté, d'un graphe pondéré, entre autres.

De plus, il offre de nombreux algorithmes possibles sur la structure de données du graphe. Un de nos tutoriels précédents couvre lesJGraphT in much more detail.

7.2. Google Guava

Google Guava est un ensemble de bibliothèques Java qui offrent une gamme de fonctions, y compris la structure de données graphiques et ses algorithmes.

Il prend en charge la création de simplesGraph,ValueGraph etNetwork. Ceux-ci peuvent être définis commeMutable ouImmutable.

7.3. Apache Commons

Apache Commons est un projet Apache qui propose des composants Java réutilisables. Cela comprend Commons Graph, qui propose une boîte à outils permettant de créer et de gérer la structure des données graphiques. Cela fournit également des algorithmes de graphes communs pour agir sur la structure de données.

7.4. Sourceforge JUNG

Java Universal Network/Graph (JUNG) est un framework Java qui fournit un langage extensible pour la modélisation, l'analyse et la visualisation de toutes les données pouvant être représentées sous forme de graphique.

JUNG prend en charge un certain nombre d'algorithmes comprenant des routines telles que la mise en cluster, la décomposition et l'optimisation.

 

Ces bibliothèques fournissent un certain nombre d'implémentations basées sur la structure de données graphique. Il existe également desmore powerful frameworks based on graphs, tels queApache Giraph, actuellement utilisés sur Facebook pour analyser le graphique formé par leurs utilisateurs, etApache TinkerPop, couramment utilisés en plus des bases de données de graphiques.

8. Conclusion

Dans cet article, nous avons présenté le graphique en tant que structure de données avec ses représentations. Nous avons défini un graphe très simple en Java à l'aide de Java Collections et également défini des parcours communs pour le graphe.

Nous avons également parlé brièvement de diverses bibliothèques disponibles en Java en dehors de la plate-forme Java, qui fournissent des implémentations de graphes.

Comme toujours, le code des exemples est disponibleover on GitHub.