1. Gambaran keseluruhan
Dalam tutorial ini, kita akan memahami konsep asas grafik sebagai struktur data .
Kami juga akan meneroka pelaksanaannya di Jawa bersama dengan pelbagai operasi yang mungkin dilakukan pada grafik. Kami juga akan membincangkan perpustakaan Java yang menawarkan pelaksanaan grafik.
2. Struktur Data Grafik
Grafik adalah struktur data untuk menyimpan data yang tersambung seperti rangkaian orang di platform media sosial.
Grafik terdiri daripada bucu dan tepi. Bucu mewakili entiti (misalnya, orang) dan kelebihan mewakili hubungan antara entiti (misalnya, persahabatan seseorang).
Mari tentukan Grafik ringkas untuk memahami perkara ini dengan lebih baik:

Di sini, kami telah menentukan graf ringkas dengan lima bucu dan enam tepi. Lingkaran adalah bucu yang mewakili orang dan garis yang menghubungkan dua bucu adalah tepi yang mewakili rakan di portal dalam talian.
Terdapat beberapa variasi grafik sederhana ini bergantung pada sifat tepi. Mari kita teliti secara ringkas di bahagian seterusnya.
Walau bagaimanapun, kami hanya akan memfokuskan pada grafik sederhana yang ditunjukkan di sini untuk contoh Java dalam tutorial ini.
2.1. Graf Terarah
Grafik yang kami tetapkan setakat ini mempunyai tepi tanpa arah. Sekiranya tepi ini mempunyai arah di dalamnya , graf yang dihasilkan dikenali sebagai graf yang diarahkan.
Contohnya dapat menunjukkan siapa yang menghantar permintaan persahabatan dalam persahabatan di portal dalam talian:

Di sini, kita dapat melihat bahawa tepinya mempunyai arah yang tetap. Bahagian tepi juga boleh menjadi dua arah.
2.2. Graf berwajaran
Sekali lagi, grafik ringkas kami mempunyai sisi yang tidak berat sebelah atau tidak berbobot. Sekiranya bahagian tepi ini mempunyai berat relatif , graf ini dikenali sebagai graf berwajaran.
Contoh aplikasi praktikal ini dapat menunjukkan seberapa lama persahabatan di portal dalam talian:

Di sini, kita dapat melihat bahawa tepi mempunyai berat yang berkaitan dengannya. Ini memberikan makna relatif kepada bahagian tepi ini.
3. Perwakilan Graf
Grafik boleh ditunjukkan dalam bentuk yang berbeza seperti matriks adjacency dan senarai adjacency. Masing-masing mempunyai kebaikan dan keburukan mereka dalam susunan yang berbeza.
Kami akan memperkenalkan perwakilan grafik ini di bahagian ini.
3.1. Matriks Adjacency
Matriks adjacency adalah matriks persegi dengan dimensi bersamaan dengan bilangan bucu dalam grafik.
Unsur-unsur matriks biasanya mempunyai nilai '0' atau '1'. Nilai '1' menunjukkan kedekatan antara bucu di baris dan lajur dan nilai '0' sebaliknya.
Mari lihat bagaimana matriks adjacency untuk grafik ringkas kami dari bahagian sebelumnya:

Perwakilan ini lebih mudah dilaksanakan dan cekap untuk membuat pertanyaan juga. Walau bagaimanapun, ia kurang cekap berkaitan dengan ruang yang dihuni .
3.2. Senarai Kecukupan
Senarai adjacency tidak lain adalah pelbagai senarai . Ukuran larik setara dengan bilangan bucu dalam grafik.
Senarai pada indeks tertentu dari array mewakili sudut bersebelahan dari sudut yang ditunjukkan oleh indeks tatasusunan itu.
Mari kita lihat seperti apa senarai kelengkapan untuk grafik ringkas kita dari bahagian sebelumnya:

Perwakilan ini agak sukar dibuat dan kurang cekap untuk membuat pertanyaan . Walau bagaimanapun, ia menawarkan kecekapan ruang yang lebih baik .
Kami akan menggunakan senarai adjacency untuk mewakili grafik dalam tutorial ini.
4. Grafik di Jawa
Java tidak mempunyai pelaksanaan default struktur data grafik.
Namun, kita dapat menerapkan grafik menggunakan Java Collections.
Mari mulakan dengan menentukan puncak:
class Vertex { String label; Vertex(String label) { this.label = label; } // equals and hashCode }
Definisi vertex di atas hanya mempunyai label tetapi ini dapat mewakili entiti yang mungkin seperti Person atau City.
Juga, perhatikan bahawa kita harus mengatasi kaedah sama () dan hashCode () kerana ini diperlukan untuk bekerja dengan Java Collections.
Seperti yang telah kita bincangkan sebelumnya, grafik tidak lain hanyalah kumpulan simpul dan tepi yang dapat ditunjukkan sebagai matriks adjacency atau senarai adjacency.
Mari kita lihat bagaimana kita dapat menentukan ini menggunakan senarai adjacency di sini:
class Graph { private Map
adjVertices; // standard constructor, getters, setters }
Seperti yang dapat kita lihat di sini, Graf kelas menggunakan Peta dari Java Collections untuk menentukan senarai yang berdekatan.
Terdapat beberapa operasi yang mungkin dilakukan pada struktur data grafik, seperti membuat, mengemas kini atau mencari melalui grafik .
Kami akan menjalani beberapa operasi yang lebih biasa dan melihat bagaimana kami dapat melaksanakannya di Java.
5. Graph Mutation Operations
To start with, we'll define some methods to mutate the graph data structure.
Let's define methods to add and remove vertices:
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)); }
These methods simply add and remove elements from the vertices Set.
Now, let's also define a method to add an edge:
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); }
This method creates a new Edge and updates the adjacent vertices Map.
In a similar way, we'll define the removeEdge() method:
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); }
Next, let's see how we can create the simple graph we have drawn earlier using the methods we've defined so far:
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; }
We'll finally define a method to get the adjacent vertices of a particular vertex:
List getAdjVertices(String label) { return adjVertices.get(new Vertex(label)); }
6. Traversing a Graph
Now that we have graph data structure and functions to create and update it defined, we can define some additional functions for traversing the graph. We need to traverse a graph to perform any meaningful action, like search within the graph.
There are two possible ways to traverse a graph, depth-first traversal and breadth-first traversal.
6.1. Depth-First Traversal
A depth-first traversal starts at an arbitrary root vertex and explores vertices as deeper as possible along each branch before exploring vertices at the same level.
Let's define a method to perform the depth-first traversal:
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; }
Here, we're using a Stack to store the vertices that need to be traversed.
Let's run this on the graph we created in the previous subsection:
assertEquals("[Bob, Rob, Maria, Alice, Mark]", depthFirstTraversal(graph, "Bob").toString());
Please note that we're using vertex “Bob” as our root for traversal here, but this can be any other vertex.
6.2. Breadth-First Traversal
Comparatively, a breadth-first traversal starts at an arbitrary root vertex and explores all neighboring vertices at the same level before going deeper in the graph.
Now let's define a method to perform the breadth-first traversal:
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; }
Note that a breadth-first traversal makes use of Queue to store the vertices which need to be traversed.
Let's again run this traversal on the same graph:
assertEquals( "[Bob, Alice, Rob, Mark, Maria]", breadthFirstTraversal(graph, "Bob").toString());
Again, the root vertex which is “Bob” here can as well be any other vertex.
7. Java Libraries for Graphs
It's not necessary to always implement the graph from scratch in Java. There are several open source and mature libraries available which offers graph implementations.
In the next few subsections, we'll go through some of these libraries.
7.1. JGraphT
JGraphT is one of the most popular libraries in Java for the graph data structure. It allows the creation of a simple graph, directed graph, weighted graph, amongst others.
Additionally, it offers many possible algorithms on the graph data structure. One of our previous tutorials covers JGraphT in much more detail.
7.2. Google Guava
Google Guava is a set of Java libraries that offer a range of functions including graph data structure and its algorithms.
It supports creating simple Graph, ValueGraph, and Network. These can be defined as Mutable or Immutable.
7.3. Apache Commons
Apache Commons is an Apache project that offers reusable Java components. This includes Commons Graph which offers a toolkit to create and manage graph data structure. This also provides common graph algorithms to operate on the data structure.
7.4. Sourceforge JUNG
Java Universal Network/Graph (JUNG) is a Java framework that provides extensible language for modeling, analysis, and visualization of any data that can be represented as a graph.
JUNG supports a number of algorithms which includes routines like clustering, decomposition, and optimization.
Perpustakaan ini menyediakan sejumlah pelaksanaan berdasarkan struktur data grafik. Terdapat juga kerangka kerja yang lebih kuat berdasarkan grafik , seperti Apache Giraph, yang saat ini digunakan di Facebook untuk menganalisis grafik yang dibentuk oleh penggunanya, dan Apache TinkerPop, yang biasanya digunakan di atas pangkalan data grafik.
8. Kesimpulannya
Dalam artikel ini, kami membincangkan grafik sebagai struktur data bersama representasinya. Kami mendefinisikan grafik yang sangat sederhana di Java menggunakan Java Collections dan juga menentukan traversal biasa untuk grafik.
Kami juga bercakap ringkas mengenai pelbagai perpustakaan yang terdapat di Java di luar platform Java yang menyediakan pelaksanaan grafik.
Seperti biasa, kod untuk contoh boleh didapati di GitHub.