Hãy nói rằng bạn muốn thực hiện một tìm kiếm theo chiều rộng của một cây nhị phân đệ quy . Làm thế nào bạn sẽ đi về nó?
Có thể chỉ sử dụng ngăn xếp cuộc gọi làm bộ nhớ phụ?
Hãy nói rằng bạn muốn thực hiện một tìm kiếm theo chiều rộng của một cây nhị phân đệ quy . Làm thế nào bạn sẽ đi về nó?
Có thể chỉ sử dụng ngăn xếp cuộc gọi làm bộ nhớ phụ?
Câu trả lời:
(Tôi cho rằng đây chỉ là một dạng bài tập suy nghĩ, hoặc thậm chí là một câu hỏi phỏng vấn / bài tập về nhà, nhưng tôi cho rằng tôi có thể tưởng tượng ra một kịch bản kỳ quái khi bạn không cho phép bất kỳ không gian heap nào vì một số lý do trình quản lý bộ nhớ? một số vấn đề thời gian chạy / hệ điều hành kỳ quái?] trong khi bạn vẫn có quyền truy cập vào ngăn xếp ...)
Theo truyền thống, chiều rộng đầu tiên sử dụng một hàng đợi, không phải là một ngăn xếp. Bản chất của hàng đợi và ngăn xếp hoàn toàn trái ngược nhau, vì vậy, cố gắng sử dụng ngăn xếp cuộc gọi (là ngăn xếp, do đó tên) làm bộ lưu trữ phụ (hàng đợi) sẽ thất bại rất nhiều, trừ khi bạn đang làm một cái gì đó ngu ngốc vô lý với ngăn xếp cuộc gọi mà bạn không nên.
Trên cùng một mã thông báo, bản chất của bất kỳ đệ quy không đuôi nào bạn cố gắng thực hiện về cơ bản là thêm một ngăn xếp vào thuật toán. Điều này làm cho nó không còn tìm kiếm lần đầu tiên trên cây nhị phân, và do đó thời gian chạy và không có gì cho BFS truyền thống không còn hoàn toàn áp dụng. Tất nhiên, bạn luôn có thể biến bất kỳ vòng lặp nào thành một cuộc gọi đệ quy, nhưng đó không phải là bất kỳ loại đệ quy có ý nghĩa nào.
Tuy nhiên, có nhiều cách, như được chứng minh bởi những người khác, để thực hiện một cái gì đó tuân theo ngữ nghĩa của BFS với một số chi phí. Nếu chi phí so sánh đắt nhưng truyền tải nút thì rẻ, như @Simon Buchan đã làm, bạn chỉ cần chạy một tìm kiếm theo chiều sâu lặp đi lặp lại, chỉ xử lý các lá. Điều này có nghĩa là không có hàng đợi tăng trưởng được lưu trữ trong heap, chỉ là một biến số độ sâu cục bộ và các ngăn xếp được xây dựng lặp đi lặp lại trên ngăn xếp cuộc gọi khi cây được lặp đi lặp lại. Và như @Patrick đã lưu ý, một cây nhị phân được hỗ trợ bởi một mảng thường được lưu trữ theo thứ tự truyền tải theo chiều rộng đầu tiên, do đó, một tìm kiếm đầu tiên trên đó sẽ là tầm thường, mà không cần hàng đợi phụ.
Nếu bạn sử dụng một mảng để sao lưu cây nhị phân, bạn có thể xác định nút tiếp theo theo đại số. if i
là một nút, thì con của nó có thể được tìm thấy tại 2i + 1
(đối với nút bên trái) và 2i + 2
(đối với nút bên phải). Hàng xóm tiếp theo của một nút được đưa ra bởi i + 1
, trừ khi i
có sức mạnh của2
Đây là mã giả cho một triển khai rất ngây thơ của tìm kiếm đầu tiên trên một cây tìm kiếm nhị phân được hỗ trợ mảng. Điều này giả định một mảng kích thước cố định và do đó một cây có chiều sâu cố định. Nó sẽ xem xét các nút không có cha mẹ và có thể tạo ra một ngăn xếp lớn không thể kiểm soát được.
bintree-bfs(bintree, elt, i)
if (i == LENGTH)
return false
else if (bintree[i] == elt)
return true
else
return bintree-bfs(bintree, elt, i+1)
Tôi không thể tìm ra cách để thực hiện đệ quy hoàn toàn (không có bất kỳ cấu trúc dữ liệu phụ trợ nào). Nhưng nếu hàng đợi Q được truyền bằng tham chiếu, thì bạn có thể có hàm đệ quy đuôi ngớ ngẩn sau đây:
BFS(Q)
{
if (|Q| > 0)
v <- Dequeue(Q)
Traverse(v)
foreach w in children(v)
Enqueue(Q, w)
BFS(Q)
}
Phương pháp sau đây đã sử dụng thuật toán DFS để có được tất cả các nút ở độ sâu cụ thể - tương tự như thực hiện BFS cho mức đó. Nếu bạn tìm ra độ sâu của cây và làm điều này cho tất cả các cấp, kết quả sẽ giống như BFS.
public void PrintLevelNodes(Tree root, int level) {
if (root != null) {
if (level == 0) {
Console.Write(root.Data);
return;
}
PrintLevelNodes(root.Left, level - 1);
PrintLevelNodes(root.Right, level - 1);
}
}
for (int i = 0; i < depth; i++) {
PrintLevelNodes(root, i);
}
Tìm chiều sâu của cây là một miếng bánh:
public int MaxDepth(Tree root) {
if (root == null) {
return 0;
} else {
return Math.Max(MaxDepth(root.Left), MaxDepth(root.Right)) + 1;
}
}
level
bằng không.
Một đệ quy BFS và DFS đơn giản trong Java:
Chỉ cần đẩy / cung cấp nút gốc của cây trong ngăn xếp / hàng đợi và gọi các hàm này.
public static void breadthFirstSearch(Queue queue) {
if (queue.isEmpty())
return;
Node node = (Node) queue.poll();
System.out.println(node + " ");
if (node.right != null)
queue.offer(node.right);
if (node.left != null)
queue.offer(node.left);
breadthFirstSearch(queue);
}
public static void depthFirstSearch(Stack stack) {
if (stack.isEmpty())
return;
Node node = (Node) stack.pop();
System.out.println(node + " ");
if (node.right != null)
stack.push(node.right);
if (node.left != null)
stack.push(node.left);
depthFirstSearch(stack);
}
Tôi tìm thấy một thuật toán đệ quy liên quan đến Breadth-First traverse rất đẹp (thậm chí là chức năng). Không phải ý tưởng của tôi, nhưng tôi nghĩ nó nên được đề cập trong chủ đề này.
Chris Okasaki giải thích thuật toán đánh số đầu tiên của mình từ ICFP 2000 tại http://okasaki.blogspot.de/2008/07/breadth-first-numbering-alerskym-in.html rất rõ ràng chỉ với 3 hình ảnh.
Việc triển khai Scala của Debasish Ghosh, mà tôi tìm thấy tại http://debasishg.blogspot.de/2008/09/breadth-first-numbering-okasakis.html , là:
trait Tree[+T]
case class Node[+T](data: T, left: Tree[T], right: Tree[T]) extends Tree[T]
case object E extends Tree[Nothing]
def bfsNumForest[T](i: Int, trees: Queue[Tree[T]]): Queue[Tree[Int]] = {
if (trees.isEmpty) Queue.Empty
else {
trees.dequeue match {
case (E, ts) =>
bfsNumForest(i, ts).enqueue[Tree[Int]](E)
case (Node(d, l, r), ts) =>
val q = ts.enqueue(l, r)
val qq = bfsNumForest(i+1, q)
val (bb, qqq) = qq.dequeue
val (aa, tss) = qqq.dequeue
tss.enqueue[org.dg.collection.BFSNumber.Tree[Int]](Node(i, aa, bb))
}
}
}
def bfsNumTree[T](t: Tree[T]): Tree[Int] = {
val q = Queue.Empty.enqueue[Tree[T]](t)
val qq = bfsNumForest(1, q)
qq.dequeue._1
}
Cách ngu ngốc:
template<typename T>
struct Node { Node* left; Node* right; T value; };
template<typename T, typename P>
bool searchNodeDepth(Node<T>* node, Node<T>** result, int depth, P pred) {
if (!node) return false;
if (!depth) {
if (pred(node->value)) {
*result = node;
}
return true;
}
--depth;
searchNodeDepth(node->left, result, depth, pred);
if (!*result)
searchNodeDepth(node->right, result, depth, pred);
return true;
}
template<typename T, typename P>
Node<T>* searchNode(Node<T>* node, P pred) {
Node<T>* result = NULL;
int depth = 0;
while (searchNodeDepth(node, &result, depth, pred) && !result)
++depth;
return result;
}
int main()
{
// a c f
// b e
// d
Node<char*>
a = { NULL, NULL, "A" },
c = { NULL, NULL, "C" },
b = { &a, &c, "B" },
f = { NULL, NULL, "F" },
e = { NULL, &f, "E" },
d = { &b, &e, "D" };
Node<char*>* found = searchNode(&d, [](char* value) -> bool {
printf("%s\n", value);
return !strcmp((char*)value, "F");
});
printf("found: %s\n", found->value);
return 0;
}
Đây là giải pháp Scala ngắn :
def bfs(nodes: List[Node]): List[Node] = {
if (nodes.nonEmpty) {
nodes ++ bfs(nodes.flatMap(_.children))
} else {
List.empty
}
}
Ý tưởng sử dụng giá trị trả về làm bộ tích lũy rất phù hợp. Có thể được thực hiện bằng các ngôn ngữ khác theo cách tương tự, chỉ cần đảm bảo rằng danh sách quy trình hàm đệ quy của bạn .
Danh sách mã kiểm tra (sử dụng cây thử @marco):
import org.scalatest.FlatSpec
import scala.collection.mutable
class Node(val value: Int) {
private val _children: mutable.ArrayBuffer[Node] = mutable.ArrayBuffer.empty
def add(child: Node): Unit = _children += child
def children = _children.toList
override def toString: String = s"$value"
}
class BfsTestScala extends FlatSpec {
// 1
// / | \
// 2 3 4
// / | | \
// 5 6 7 8
// / | | \
// 9 10 11 12
def tree(): Node = {
val root = new Node(1)
root.add(new Node(2))
root.add(new Node(3))
root.add(new Node(4))
root.children(0).add(new Node(5))
root.children(0).add(new Node(6))
root.children(2).add(new Node(7))
root.children(2).add(new Node(8))
root.children(0).children(0).add(new Node(9))
root.children(0).children(0).add(new Node(10))
root.children(2).children(0).add(new Node(11))
root.children(2).children(0).add(new Node(12))
root
}
def bfs(nodes: List[Node]): List[Node] = {
if (nodes.nonEmpty) {
nodes ++ bfs(nodes.flatMap(_.children))
} else {
List.empty
}
}
"BFS" should "work" in {
println(bfs(List(tree())))
}
}
Đầu ra:
List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
Đây là một triển khai python:
graph = {'A': ['B', 'C'],
'B': ['C', 'D'],
'C': ['D'],
'D': ['C'],
'E': ['F'],
'F': ['C']}
def bfs(paths, goal):
if not paths:
raise StopIteration
new_paths = []
for path in paths:
if path[-1] == goal:
yield path
last = path[-1]
for neighbor in graph[last]:
if neighbor not in path:
new_paths.append(path + [neighbor])
yield from bfs(new_paths, goal)
for path in bfs([['A']], 'D'):
print(path)
Đây là một triển khai Scala 2.11.4 của BFS đệ quy. Tôi đã hy sinh tối ưu hóa cuộc gọi đuôi để ngắn gọn, nhưng phiên bản TCOd rất giống nhau. Xem thêm bài viết của @snv .
import scala.collection.immutable.Queue
object RecursiveBfs {
def bfs[A](tree: Tree[A], target: A): Boolean = {
bfs(Queue(tree), target)
}
private def bfs[A](forest: Queue[Tree[A]], target: A): Boolean = {
forest.dequeueOption exists {
case (E, tail) => bfs(tail, target)
case (Node(value, _, _), _) if value == target => true
case (Node(_, l, r), tail) => bfs(tail.enqueue(List(l, r)), target)
}
}
sealed trait Tree[+A]
case class Node[+A](data: A, left: Tree[A], right: Tree[A]) extends Tree[A]
case object E extends Tree[Nothing]
}
Những điều sau đây có vẻ khá tự nhiên đối với tôi, sử dụng Haskell. Lặp lại đệ quy qua các cấp của cây (ở đây tôi thu thập các tên thành một chuỗi có thứ tự lớn để hiển thị đường dẫn qua cây):
data Node = Node {name :: String, children :: [Node]}
aTree = Node "r" [Node "c1" [Node "gc1" [Node "ggc1" []], Node "gc2" []] , Node "c2" [Node "gc3" []], Node "c3" [] ]
breadthFirstOrder x = levelRecurser [x]
where levelRecurser level = if length level == 0
then ""
else concat [name node ++ " " | node <- level] ++ levelRecurser (concat [children node | node <- level])
Dưới đây là một triển khai Python duyệt qua đệ quy BFS, làm việc cho một biểu đồ không có chu kỳ.
def bfs_recursive(level):
'''
@params level: List<Node> containing the node for a specific level.
'''
next_level = []
for node in level:
print(node.value)
for child_node in node.adjency_list:
next_level.append(child_node)
if len(next_level) != 0:
bfs_recursive(next_level)
class Node:
def __init__(self, value):
self.value = value
self.adjency_list = []
Tôi muốn thêm xu của mình vào câu trả lời hàng đầu ở chỗ nếu ngôn ngữ hỗ trợ một cái gì đó như trình tạo, bfs có thể được thực hiện đồng quy.
Để bắt đầu, câu trả lời của @ Tanzelax đọc:
Theo truyền thống, chiều rộng đầu tiên sử dụng một hàng đợi, không phải là một ngăn xếp. Bản chất của một hàng đợi và một ngăn xếp hoàn toàn trái ngược nhau, vì vậy cố gắng sử dụng ngăn xếp cuộc gọi (là một ngăn xếp, do đó tên) làm bộ lưu trữ phụ (một hàng đợi) sẽ thất bại khá nhiều
Thật vậy, ngăn xếp của hàm gọi thông thường sẽ không hoạt động như một ngăn xếp thông thường. Nhưng hàm tạo sẽ đình chỉ việc thực thi hàm để nó cho chúng ta cơ hội sinh ra các cấp con tiếp theo mà không đào sâu vào hậu duệ của nút.
Đoạn mã sau là bfs đệ quy trong Python.
def bfs(root):
yield root
for n in bfs(root):
for c in n.children:
yield c
Trực giác ở đây là:
Tôi đã phải thực hiện một giao dịch heap mà đầu ra theo thứ tự BFS. Nó không thực sự là BFS nhưng hoàn thành nhiệm vụ tương tự.
private void getNodeValue(Node node, int index, int[] array) {
array[index] = node.value;
index = (index*2)+1;
Node left = node.leftNode;
if (left!=null) getNodeValue(left,index,array);
Node right = node.rightNode;
if (right!=null) getNodeValue(right,index+1,array);
}
public int[] getHeap() {
int[] nodes = new int[size];
getNodeValue(root,0,nodes);
return nodes;
}
Đặt v là đỉnh bắt đầu
Đặt G là đồ thị trong câu hỏi
Sau đây là mã giả mà không sử dụng hàng đợi
Initially label v as visited as you start from v
BFS(G,v)
for all adjacent vertices w of v in G:
if vertex w is not visited:
label w as visited
for all adjacent vertices w of v in G:
recursively call BFS(G,w)
BFS cho cây nhị phân (hoặc n-ary) có thể được thực hiện đệ quy mà không cần hàng đợi như sau (ở đây trong Java):
public class BreathFirst {
static class Node {
Node(int value) {
this(value, 0);
}
Node(int value, int nChildren) {
this.value = value;
this.children = new Node[nChildren];
}
int value;
Node[] children;
}
static void breathFirst(Node root, Consumer<? super Node> printer) {
boolean keepGoing = true;
for (int level = 0; keepGoing; level++) {
keepGoing = breathFirst(root, printer, level);
}
}
static boolean breathFirst(Node node, Consumer<? super Node> printer, int depth) {
if (depth < 0 || node == null) return false;
if (depth == 0) {
printer.accept(node);
return true;
}
boolean any = false;
for (final Node child : node.children) {
any |= breathFirst(child, printer, depth - 1);
}
return any;
}
}
Một ví dụ về in số ngang 1-12 theo thứ tự tăng dần:
public static void main(String... args) {
// 1
// / | \
// 2 3 4
// / | | \
// 5 6 7 8
// / | | \
// 9 10 11 12
Node root = new Node(1, 3);
root.children[0] = new Node(2, 2);
root.children[1] = new Node(3);
root.children[2] = new Node(4, 2);
root.children[0].children[0] = new Node(5, 2);
root.children[0].children[1] = new Node(6);
root.children[2].children[0] = new Node(7, 2);
root.children[2].children[1] = new Node(8);
root.children[0].children[0].children[0] = new Node(9);
root.children[0].children[0].children[1] = new Node(10);
root.children[2].children[0].children[0] = new Node(11);
root.children[2].children[0].children[1] = new Node(12);
breathFirst(root, n -> System.out.println(n.value));
}
#include <bits/stdc++.h>
using namespace std;
#define Max 1000
vector <int> adj[Max];
bool visited[Max];
void bfs_recursion_utils(queue<int>& Q) {
while(!Q.empty()) {
int u = Q.front();
visited[u] = true;
cout << u << endl;
Q.pop();
for(int i = 0; i < (int)adj[u].size(); ++i) {
int v = adj[u][i];
if(!visited[v])
Q.push(v), visited[v] = true;
}
bfs_recursion_utils(Q);
}
}
void bfs_recursion(int source, queue <int>& Q) {
memset(visited, false, sizeof visited);
Q.push(source);
bfs_recursion_utils(Q);
}
int main(void) {
queue <int> Q;
adj[1].push_back(2);
adj[1].push_back(3);
adj[1].push_back(4);
adj[2].push_back(5);
adj[2].push_back(6);
adj[3].push_back(7);
bfs_recursion(1, Q);
return 0;
}
Dưới đây là một triển khai JavaScript thực hiện đệ quy đầu tiên theo chiều rộng với đệ quy sâu đầu tiên. Tôi đang lưu trữ các giá trị nút ở mỗi độ sâu bên trong một mảng, bên trong hàm băm. Nếu một mức đã tồn tại (chúng ta có xung đột), vì vậy chúng ta chỉ cần đẩy đến mảng ở cấp đó. Bạn cũng có thể sử dụng một mảng thay vì một đối tượng JavaScript vì các cấp của chúng tôi là số và có thể đóng vai trò là các chỉ số mảng. Bạn có thể trả về các nút, giá trị, chuyển đổi thành Danh sách được liên kết hoặc bất cứ điều gì bạn muốn. Tôi chỉ trả lại các giá trị vì đơn giản.
BinarySearchTree.prototype.breadthFirstRec = function() {
var levels = {};
var traverse = function(current, depth) {
if (!current) return null;
if (!levels[depth]) levels[depth] = [current.value];
else levels[depth].push(current.value);
traverse(current.left, depth + 1);
traverse(current.right, depth + 1);
};
traverse(this.root, 0);
return levels;
};
var bst = new BinarySearchTree();
bst.add(20, 22, 8, 4, 12, 10, 14, 24);
console.log('Recursive Breadth First: ', bst.breadthFirstRec());
/*Recursive Breadth First:
{ '0': [ 20 ],
'1': [ 8, 22 ],
'2': [ 4, 12, 24 ],
'3': [ 10, 14 ] } */
Dưới đây là một ví dụ về Breadth First Traversal thực tế bằng cách sử dụng phương pháp lặp.
BinarySearchTree.prototype.breadthFirst = function() {
var result = '',
queue = [],
current = this.root;
if (!current) return null;
queue.push(current);
while (current = queue.shift()) {
result += current.value + ' ';
current.left && queue.push(current.left);
current.right && queue.push(current.right);
}
return result;
};
console.log('Breadth First: ', bst.breadthFirst());
//Breadth First: 20 8 22 4 12 24 10 14
Sau đây là mã của tôi để thực hiện đệ quy hoàn toàn lần đầu tiên tìm kiếm đồ thị hai chiều mà không sử dụng vòng lặp và hàng đợi.
public class Graph
{
public int V;
public LinkedList<Integer> adj[];
Graph(int v)
{
V = v;
adj = new LinkedList[v];
for (int i=0; i<v; ++i)
adj[i] = new LinkedList<>();
}
void addEdge(int v,int w)
{
adj[v].add(w);
adj[w].add(v);
}
public LinkedList<Integer> getAdjVerted(int vertex)
{
return adj[vertex];
}
public String toString()
{
String s = "";
for (int i=0;i<adj.length;i++)
{
s = s +"\n"+i +"-->"+ adj[i] ;
}
return s;
}
}
//BFS IMPLEMENTATION
public static void recursiveBFS(Graph graph, int vertex,boolean visited[], boolean isAdjPrinted[])
{
if (!visited[vertex])
{
System.out.print(vertex +" ");
visited[vertex] = true;
}
if(!isAdjPrinted[vertex])
{
isAdjPrinted[vertex] = true;
List<Integer> adjList = graph.getAdjVerted(vertex);
printAdjecent(graph, adjList, visited, 0,isAdjPrinted);
}
}
public static void recursiveBFS(Graph graph, List<Integer> vertexList, boolean visited[], int i, boolean isAdjPrinted[])
{
if (i < vertexList.size())
{
recursiveBFS(graph, vertexList.get(i), visited, isAdjPrinted);
recursiveBFS(graph, vertexList, visited, i+1, isAdjPrinted);
}
}
public static void printAdjecent(Graph graph, List<Integer> list, boolean visited[], int i, boolean isAdjPrinted[])
{
if (i < list.size())
{
if (!visited[list.get(i)])
{
System.out.print(list.get(i)+" ");
visited[list.get(i)] = true;
}
printAdjecent(graph, list, visited, i+1, isAdjPrinted);
}
else
{
recursiveBFS(graph, list, visited, 0, isAdjPrinted);
}
}
C # thực hiện thuật toán tìm kiếm theo chiều rộng đệ quy cho cây nhị phân.
Trực quan hóa dữ liệu cây nhị phân
IDictionary<string, string[]> graph = new Dictionary<string, string[]> {
{"A", new [] {"B", "C"}},
{"B", new [] {"D", "E"}},
{"C", new [] {"F", "G"}},
{"E", new [] {"H"}}
};
void Main()
{
var pathFound = BreadthFirstSearch("A", "H", new string[0]);
Console.WriteLine(pathFound); // [A, B, E, H]
var pathNotFound = BreadthFirstSearch("A", "Z", new string[0]);
Console.WriteLine(pathNotFound); // []
}
IEnumerable<string> BreadthFirstSearch(string start, string end, IEnumerable<string> path)
{
if (start == end)
{
return path.Concat(new[] { end });
}
if (!graph.ContainsKey(start)) { return new string[0]; }
return graph[start].SelectMany(letter => BreadthFirstSearch(letter, end, path.Concat(new[] { start })));
}
Nếu bạn muốn thuật toán hoạt động không chỉ với cây nhị phân mà với đồ thị, có thể có hai và nhiều nút trỏ đến cùng một nút khác, bạn phải tránh tự quay vòng bằng cách giữ danh sách các nút đã truy cập. Việc thực hiện có thể giống như thế này.
IDictionary<string, string[]> graph = new Dictionary<string, string[]> {
{"A", new [] {"B", "C"}},
{"B", new [] {"D", "E"}},
{"C", new [] {"F", "G", "E"}},
{"E", new [] {"H"}}
};
void Main()
{
var pathFound = BreadthFirstSearch("A", "H", new string[0], new List<string>());
Console.WriteLine(pathFound); // [A, B, E, H]
var pathNotFound = BreadthFirstSearch("A", "Z", new string[0], new List<string>());
Console.WriteLine(pathNotFound); // []
}
IEnumerable<string> BreadthFirstSearch(string start, string end, IEnumerable<string> path, IList<string> visited)
{
if (start == end)
{
return path.Concat(new[] { end });
}
if (!graph.ContainsKey(start)) { return new string[0]; }
return graph[start].Aggregate(new string[0], (acc, letter) =>
{
if (visited.Contains(letter))
{
return acc;
}
visited.Add(letter);
var result = BreadthFirstSearch(letter, end, path.Concat(new[] { start }), visited);
return acc.Concat(result).ToArray();
});
}
Tôi đã thực hiện một chương trình sử dụng c ++ đang hoạt động trong biểu đồ khớp và tách rời.
#include <queue>
#include "iostream"
#include "vector"
#include "queue"
using namespace std;
struct Edge {
int source,destination;
};
class Graph{
int V;
vector<vector<int>> adjList;
public:
Graph(vector<Edge> edges,int V){
this->V = V;
adjList.resize(V);
for(auto i : edges){
adjList[i.source].push_back(i.destination);
// adjList[i.destination].push_back(i.source);
}
}
void BFSRecursivelyJoinandDisjointtGraphUtil(vector<bool> &discovered, queue<int> &q);
void BFSRecursivelyJointandDisjointGraph(int s);
void printGraph();
};
void Graph :: printGraph()
{
for (int i = 0; i < this->adjList.size(); i++)
{
cout << i << " -- ";
for (int v : this->adjList[i])
cout <<"->"<< v << " ";
cout << endl;
}
}
void Graph ::BFSRecursivelyJoinandDisjointtGraphUtil(vector<bool> &discovered, queue<int> &q) {
if (q.empty())
return;
int v = q.front();
q.pop();
cout << v <<" ";
for (int u : this->adjList[v])
{
if (!discovered[u])
{
discovered[u] = true;
q.push(u);
}
}
BFSRecursivelyJoinandDisjointtGraphUtil(discovered, q);
}
void Graph ::BFSRecursivelyJointandDisjointGraph(int s) {
vector<bool> discovered(V, false);
queue<int> q;
for (int i = s; i < V; i++) {
if (discovered[i] == false)
{
discovered[i] = true;
q.push(i);
BFSRecursivelyJoinandDisjointtGraphUtil(discovered, q);
}
}
}
int main()
{
vector<Edge> edges =
{
{0, 1}, {0, 2}, {1, 2}, {2, 0}, {2,3},{3,3}
};
int V = 4;
Graph graph(edges, V);
// graph.printGraph();
graph.BFSRecursivelyJointandDisjointGraph(2);
cout << "\n";
edges = {
{0,4},{1,2},{1,3},{1,4},{2,3},{3,4}
};
Graph graph2(edges,5);
graph2.BFSRecursivelyJointandDisjointGraph(0);
return 0;
}