Memeriksa sama ada Grafik Java mempunyai Kitaran

1. Gambaran keseluruhan

Dalam tutorial ringkas ini, kita akan belajar bagaimana kita dapat mengesan kitaran dalam grafik yang diarahkan.

2. Perwakilan Graf

Untuk tutorial ini, kami akan mengikuti perwakilan grafik senarai adjacency.

Pertama, mari kita mulakan dengan menentukan Vertex di Java:

public class Vertex { private String label; private boolean beingVisited; private boolean visited; private List adjacencyList; public Vertex(String label) { this.label = label; this.adjacencyList = new ArrayList(); } public void addNeighbor(Vertex adjacent) { this.adjacencyList.add(adjacent); } //getters and setters }

Di sini, adjacencyList dari bucu v menyimpan senarai semua bucu bersebelahan dengan v . Kaedah addNeighbor () menambah bucu sebelah ke senarai berdekatan v .

Kami juga telah ditakrifkan dua boolean parameter, beingVisited dan melawat, yang mewakili sama ada nod sedang melawat atau telah dilawati.

Grafik boleh dianggap sebagai kumpulan bucu atau simpul yang dihubungkan melalui pinggir.

Oleh itu, mari kita cepat mewakili Grafik di Java:

public class Graph { private List vertices; public Graph() { this.vertices = new ArrayList(); } public void addVertex(Vertex vertex) { this.vertices.add(vertex); } public void addEdge(Vertex from, Vertex to) { from.addNeighbor(to); } // ... }

Kami akan menggunakan kaedah addVertex () dan addEdge () untuk menambah bucu dan tepi baru dalam grafik kami.

3. Pengesanan Kitaran

Untuk mengesan kitaran dalam graf yang diarahkan, kami akan menggunakan variasi traversal DFS :

  • Angkat bucu v yang tidak dilawati dan tandakan keadaannya sebagai dilawati
  • Bagi setiap jiran mercu u daripada v, menyemak:
    • Sekiranya anda sudah berada dalam keadaan sedang Dikunjungi , ini jelas menunjukkan bahawa terdapat tepi belakang dan kitaran telah dikesan
    • Sekiranya anda masih dalam keadaan tidak dilawati, kami akan secara berulang-ulang mengunjungi anda secara mendalam
  • Kemas kini bendera vertex v 's Visited ke false dan bendera yang dikunjungi menjadi true

Perhatikan bahawa kesemua mercu graf kami pada mulanya dalam keadaan tidak dilawati kerana kedua-dua mereka beingVisited dan melawat bendera dimulakan dengan palsu .

Sekarang mari kita lihat penyelesaian Java kami:

public boolean hasCycle(Vertex sourceVertex) { sourceVertex.setBeingVisited(true); for (Vertex neighbor : sourceVertex.getAdjacencyList()) { if (neighbor.isBeingVisited()) { // backward edge exists return true; } else if (!neighbor.isVisited() && hasCycle(neighbor)) { return true; } } sourceVertex.setBeingVisited(false); sourceVertex.setVisited(true); return false; }

Kita boleh menggunakan bucu dalam grafik untuk menjadi sumber atau bucu permulaan.

Untuk grafik yang terputus, kita perlu menambahkan kaedah pembungkus tambahan:

public boolean hasCycle() { for (Vertex vertex : vertices) { if (!vertex.isVisited() && hasCycle(vertex)) { return true; } } return false; }

Ini untuk memastikan bahawa kita mengunjungi setiap komponen grafik yang terputus untuk mengesan kitaran.

4. Ujian Pelaksanaan

Mari kita perhatikan graf diarahkan siklik di bawah:

Kami dapat menulis JUnit dengan cepat untuk mengesahkan kaedah hasCycle () kami untuk grafik ini:

@Test public void givenGraph_whenCycleExists_thenReturnTrue() { Vertex vertexA = new Vertex("A"); Vertex vertexB = new Vertex("B"); Vertex vertexC = new Vertex("C") Vertex vertexD = new Vertex("D"); Graph graph = new Graph(); graph.addVertex(vertexA); graph.addVertex(vertexB); graph.addVertex(vertexC); graph.addVertex(vertexD); graph.addEdge(vertexA, vertexB); graph.addEdge(vertexB, vertexC); graph.addEdge(vertexC, vertexA); graph.addEdge(vertexD, vertexC); assertTrue(graph.hasCycle()); }

Di sini, kaedah hasCycle () kami kembali benar menunjukkan bahawa graf kami adalah kitaran.

5. Kesimpulan

Dalam tutorial ini, kami belajar bagaimana memeriksa apakah suatu siklus ada dalam grafik yang diarahkan di Java.

Seperti biasa, pelaksanaan kod dengan contoh boleh didapati di Github.