प्रदर्शन पहले चौड़ाई


152

मान लें कि आप बाइनरी ट्री की एक चौड़ाई-प्रथम खोज को पुनरावर्ती रूप से लागू करना चाहते थे । आप इसके बारे में कैसे जायेंगे?

क्या सहायक भंडारण के रूप में केवल कॉल-स्टैक का उपयोग करना संभव है?


14
बहुत अच्छा सवाल है। यह बिल्कुल सीधा नहीं है। मूल रूप से आप केवल स्टैक का उपयोग करके BFS को लागू करने के लिए कह रहे हैं।
सिसिस

4
सिर्फ एक ढेर के साथ पुनरावर्ती? इससे मेरा सिर दुखता है।
केविन फ्रीडहेम

11
मैं आमतौर पर पुनरावर्ती व्यवहार को हटाने के लिए एक स्टैक का उपयोग करता हूं
न्यूटोपियन

यदि मैं एक अधिकतम ढेर पर BFS का उपयोग करता हूं, तो मुझे आश्चर्य है कि क्या नीचे दिए गए समाधान ठीक से काम करते हैं? कोई विचार ?
Jay D

जवाबों:


122

(मैं मान रहा हूँ कि यह सिर्फ किसी प्रकार का विचार अभ्यास है, या यहां तक ​​कि एक चाल होमवर्क / साक्षात्कार प्रश्न भी है, लेकिन मुझे लगता है कि मैं कुछ विचित्र परिदृश्यों की कल्पना कर सकता हूं, जहां आपको किसी कारण से किसी भी स्थान को अनुमति नहीं है मेमोरी मैनेजर? कुछ विचित्र रनटाइम / ओएस मुद्दे?] जबकि आपके पास अभी भी स्टैक तक पहुंच है ...)

चौड़ाई-प्रथम ट्रैवर्सल पारंपरिक रूप से एक कतार का उपयोग करता है, एक स्टैक नहीं। एक कतार और एक स्टैक की प्रकृति बहुत अधिक विपरीत हैं, इसलिए कॉल स्टैक (जो एक स्टैक है, इसलिए नाम) का उपयोग करने की कोशिश कर रहा है क्योंकि सहायक भंडारण (एक कतार) के रूप में विफलता के लिए बहुत अधिक बर्बाद है, जब तक आप नहीं कर रहे हैं मूर्खतापूर्ण रूप से कॉल स्टैक के साथ कुछ हास्यास्पद है जो आपको नहीं होना चाहिए।

उसी टोकन पर, आपके द्वारा लागू किए जाने वाले किसी भी गैर-पूंछ पुनरावर्तन की प्रकृति अनिवार्य रूप से एल्गोरिथ्म में एक स्टैक जोड़ रही है। इससे बाइनरी ट्री पर पहले ब्रेड की खोज नहीं होती है, और इस तरह पारंपरिक बीएफएस के लिए रन-टाइम और व्हाट्सएप अब पूरी तरह से लागू नहीं होता है। बेशक, आप हमेशा किसी भी लूप को पुनरावर्ती कॉल में बदल सकते हैं, लेकिन यह किसी भी प्रकार की सार्थक पुनरावृत्ति नहीं है।

हालांकि, ऐसे तरीके हैं, जो दूसरों द्वारा दिखाए गए हैं, कुछ लागत पर बीएफएस के शब्दार्थ का पालन करने के लिए। यदि तुलना की लागत महंगी है, लेकिन नोड ट्रैवर्स सस्ता है, तो @Simon बुकान ने किया, आप केवल एक पुनरावृत्त गहराई-पहली खोज को चला सकते हैं, केवल पत्तियों को संसाधित कर सकते हैं। इसका मतलब यह होगा कि ढेर में कोई बढ़ती हुई कतार नहीं है, बस एक स्थानीय गहराई वाला चर है, और कॉल स्टैक के ऊपर और ऊपर ढेर बनाए जा रहे हैं क्योंकि पेड़ पर बार-बार निशान पड़ते हैं। जैसा कि @Prickrick ने उल्लेख किया है, एक सरणी द्वारा समर्थित एक द्विआधारी पेड़ को आमतौर पर चौड़ाई-प्रथम ट्रैवर्सल ऑर्डर में संग्रहीत किया जाता है, इसलिए उस पर एक चौड़ाई-पहली खोज तुच्छ होगी, सहायक कतार की आवश्यकता के बिना भी।


10
यह वास्तव में सिर्फ एक सोचा व्यायाम है। मैं वास्तव में ऐसी स्थिति की कल्पना नहीं कर सकता, जिसमें आप वास्तव में ऐसा करना चाहते हैं। अच्छी तरह से सोचा जवाब के लिए धन्यवाद!
नैट

2
" लेकिन मुझे लगता है कि मैं कुछ विचित्र परिदृश्यों की कल्पना कर सकता हूं, जहां आपको किसी कारण से किसी भी जगह को अनुमति नहीं दी जाती है ": डननो, मैं एक एम्बेडेड वातावरण की कल्पना कर सकता हूं जहां केवल स्टैक (किसी भी रीड-ओनली मेमोरी स्पेस के साथ) उपलब्ध है (यह उपलब्ध है) वास्तव में काफी आसान और कुशल सॉफ्टवेयर लिखने के लिए ढेर का उपयोग किए बिना यदि आप जानते हैं कि वास्तव में आपका कार्यक्रम क्या करने जा रहा है, जो आमतौर पर एम्बेडेड सॉफ़्टवेयर में होता है)। तो यह मेरे लिए "विचित्र" नहीं है। असामान्य, शायद, लेकिन विचित्र नहीं।
थॉमस

मुझे लगता है कि आपके उत्तर में इस लेख ( ibm.com/developerworks/aix/library/au-aix-stack-tree-traversal ) का संदर्भ हो सकता है । यह है कि आप अपने जवाब के दूसरे भाग में लिखा है के बारे में एक कार्यान्वयन से पता चलता
incud

25

यदि आप बाइनरी ट्री को वापस करने के लिए एक सरणी का उपयोग करते हैं, तो आप अगले नोड को बीजगणितीय रूप से निर्धारित कर सकते हैं। यदि iएक नोड है, तो उसके बच्चों को 2i + 1(बाएं नोड के लिए) और 2i + 2(दाएं नोड के लिए ) पाया जा सकता है । एक नोड के अगले पड़ोसी द्वारा दिया जाता है i + 1, जब तक iकि एक शक्ति नहीं होती है2

यहाँ एक सरणी समर्थित बाइनरी सर्च ट्री पर पहले खोज के लिए बहुत भोली कार्यान्वयन के लिए स्यूडोकोड है। यह एक निश्चित आकार के सरणी को मानता है और इसलिए एक निश्चित गहराई वाला पेड़ है। यह पेरेंटलेस नोड्स को देखेगा, और एक बड़े पैमाने पर एक विशालकाय स्टैक बना सकता है।

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)        

1
अच्छा लगा। मैंने इस तथ्य की अनदेखी की कि हम एक बाइनरी ट्री के साथ काम कर रहे हैं। इंडेक्स को डीएफएस का उपयोग करके सौंपा जा सकता है। BTW, आप पहले मामले में गलत रिटर्न भूल गए।
सिसिस

मुझे लगता है कि मैं कतार विधि को पसंद करता हूं; पी। जोड़ा गया झूठा।
पैट्रिक मैकमुर्ची

1
चतुर। एक सरणी में नोड्स को संग्रहीत करने और उन्हें बीजगणितीय रूप से संदर्भित करने का विचार मुझे नहीं हुआ था।
नैट

19

मैं इसे पूरी तरह से पुनरावर्ती (किसी भी सहायक डेटा-संरचना के बिना) करने का कोई तरीका नहीं खोज सका। लेकिन अगर कतार क्यू को संदर्भ द्वारा पारित किया जाता है, तो आप निम्न मूर्खतापूर्ण पूंछ पुनरावर्ती कार्य कर सकते हैं:

BFS(Q)
{
  if (|Q| > 0)
     v <- Dequeue(Q)
     Traverse(v)
     foreach w in children(v)
        Enqueue(Q, w)    

     BFS(Q)
}

6
यह अप्राकृतिक तरीका है, स्वच्छ और सही कार्य के लिए पुनरावर्ती को जोड़ने के लिए।
मिस्टेरियन

पूरी तरह से असहमत - मुझे यह अधिक स्वाभाविक लगता है - और भी अधिक उपयोगी; जब आप परतों के माध्यम से जाते हैं, तो आप इस विधि का विस्तार कर सकते हैं, जैसे कि आप परतों के माध्यम से जाते हैं
टॉम गोल्डन

15

निम्नलिखित विधि ने एक विशेष गहराई में सभी नोड्स प्राप्त करने के लिए एक डीएफएस एल्गोरिथ्म का उपयोग किया - जो उस स्तर के लिए बीएफएस करने के समान है। यदि आप पेड़ की गहराई का पता लगाते हैं और सभी स्तरों के लिए ऐसा करते हैं, तो परिणाम बीएफएस के समान होंगे।

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);
}

पेड़ की गहराई का पता लगाना केक का एक टुकड़ा है:

public int MaxDepth(Tree root) {
    if (root == null) {
        return 0;
    } else {
        return Math.Max(MaxDepth(root.Left), MaxDepth(root.Right)) + 1;
    }
}

कृपया अपने कोड फ़ॉर्मेटिंग पर थोड़ा अधिक ध्यान दें। मैंने कुछ बदलाव किए।
मीका

लेकिन, पकड़ो ... क्या यह बीएफएस के बजाय डीएफएस है? क्योंकि PrintLevelNodes levelशून्य होने तक वापस नहीं आता है।
हेरिंगटन डार्कहोल

1
@ हेरिंगटनडार्कहोलमे, सही। यह DFS खोज करता है, लेकिन आउटपुट मानों के रूप में अगर यह एक स्तर के लिए BFS किया था। यह इंगित करने के लिए धन्यवाद।
Sanj

1
@ संजय, यह वास्तव में एक अच्छा प्रदर्शन है कि कोई व्यक्ति डीएफएस-ऑर्डर में नोड्स पर कुछ कार्रवाई कैसे कर सकता है। यह जरूरी नहीं है कि डीएफएस-ऑर्डर में कोई वास्तव में "टच" नोड्स कैसे करेगा, लेकिन निश्चित रूप से डीएफएस ऑर्डर में नोड्स पर पुनरावृत्ति "अधिनियम" करने की अनुमति देगा, इस मामले में उनके मूल्यों को छापते हैं।
बंकर

8

जावा में एक साधारण बीएफएस और डीएफएस पुनरावृत्ति:
स्टैक / कतार में पेड़ के रूट नोड को बस धक्का / प्रस्ताव दें और अपने कार्यों को कॉल करें।

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);
}

4
डीएफएस के लिए एक पैरामीटर के रूप में स्टैक पास करना थोड़ा अजीब है, क्योंकि आपके पास पहले से ही निहित स्टैक है। इसके अलावा सवाल केवल डेटा स्टैक के रूप में कॉल स्टैक का उपयोग करने का था।
व्लादिच

4

मुझे एक बहुत सुंदर पुनरावर्ती (यहां तक ​​कि कार्यात्मक) चौड़ाई-प्रथम ट्रैवर्सल संबंधित एल्गोरिथ्म मिला। मेरा विचार नहीं है, लेकिन मुझे लगता है कि इस विषय में इसका उल्लेख किया जाना चाहिए।

क्रिस ओकासाकी, ICok 2000 से http://okasaki.blogspot.de/2008/07/breadth-first-numbering-algorithm-in.html पर अपनी चौड़ाई-पहली नंबर एल्गोरिथ्म को केवल 3 चित्रों के साथ बहुत स्पष्ट रूप से बताते हैं ।

देबाशीष घोष का स्काला कार्यान्वयन, जो मुझे http://debasishg.blogspot.de/2008/09/breadth-first-numbering-okasakis.html पर मिला है , यह है:

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
}

सुंदर एल्गोरिथ्म के लिए +1। हालाँकि, मैंने पाया कि यह अभी भी एक कतार का उपयोग कर रहा है। "नियम 3" का बायाँ भाग वास्तव में छल और चक्रव्यूह है।
ल्यूक ली

3

गूंगा तरीका:

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;
}

3

यहाँ लघु स्काला समाधान है:

  def bfs(nodes: List[Node]): List[Node] = {
    if (nodes.nonEmpty) {
      nodes ++ bfs(nodes.flatMap(_.children))
    } else {
      List.empty
    }
  }

संचायक के रूप में वापसी मूल्य का उपयोग करने का विचार अच्छी तरह से अनुकूल है। अन्य भाषाओं में इसी तरह से लागू किया जा सकता है, बस यह सुनिश्चित करें कि आपके पुनरावर्ती फ़ंक्शन प्रक्रिया नोड्स की सूची

टेस्ट कोड लिस्टिंग (@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())))
  }
}

आउटपुट:

List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)

2

यहाँ एक अजगर कार्यान्वयन है:

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)

2

यहाँ पुनरावर्ती बीएफएस का स्कैला 2.11.4 कार्यान्वयन है। मैंने संक्षिप्तता के लिए टेल-कॉल ऑप्टिमाइज़ेशन का त्याग किया है, लेकिन TCOd संस्करण बहुत समान है। @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]
}

2

Haskell का उपयोग करते हुए, निम्नलिखित मुझे बहुत स्वाभाविक लगता है। पेड़ के स्तरों पर पुनरावृत्ति करें

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])

2

यहां एक बीएफएस पुनरावर्ती ट्रैवर्सल पायथन कार्यान्वयन है, जो बिना किसी चक्र के ग्राफ के लिए काम कर रहा है।

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 = []

2

मैं अपने सेंट को शीर्ष उत्तर में जोड़ना चाहूंगा कि अगर भाषा जनरेटर जैसी किसी चीज का समर्थन करती है, तो सह-पुनरावर्ती रूप से बीएफएस किया जा सकता है।

शुरू करने के लिए, @ Tanzelax का जवाब पढ़ता है:

चौड़ाई-प्रथम ट्रैवर्सल पारंपरिक रूप से एक कतार का उपयोग करता है, एक स्टैक नहीं। एक कतार और एक स्टैक की प्रकृति बहुत अधिक विपरीत हैं, इसलिए कॉल स्टैक (जो एक स्टैक है, इसलिए नाम) का उपयोग करने की कोशिश कर रहा है क्योंकि सहायक भंडारण (एक कतार) विफलता के लिए बहुत अधिक बर्बाद है

वास्तव में, साधारण फ़ंक्शन कॉल का स्टैक सामान्य स्टैक की तरह व्यवहार नहीं करेगा। लेकिन जनरेटर फ़ंक्शन फ़ंक्शन के निष्पादन को निलंबित कर देगा, इसलिए यह नोड के गहरे वंशज में बिना मोड़े नोड्स के बच्चों के अगले स्तर का उत्पादन करने का मौका देता है।

निम्नलिखित कोड पायथन में पुनरावर्ती bfs है।

def bfs(root):
  yield root
  for n in bfs(root):
    for c in n.children:
      yield c

यहाँ अंतर्ज्ञान है:

  1. bfs पहले रूट को पहले परिणाम के रूप में लौटाएगा
  2. मान लीजिए कि हमारे पास पहले से ही bfs अनुक्रम है, bfs में तत्वों का अगला स्तर अनुक्रम में पिछले नोड के तात्कालिक बच्चे हैं
  3. उपरोक्त दो प्रक्रियाओं को दोहराएं

मैं पायथन को नहीं जानता लेकिन मुझे लगता है कि आपका कोड इस C # कोड में बदल जाता है । यह BFS ट्रैवर्सल करता है लेकिन स्टैकओवरफ्लो अपवाद के साथ क्रैश होता है। मुझे अब तक इस बात का पता नहीं चला है। हालांकि, मैंने एल्गोरिथ्म को संशोधित किया ताकि यह बंद हो जाए (और बेहतर प्रदर्शन करता है)। आप मेरे काम का नमूना यहां देखें
एडम साइमन

1

मुझे एक ढेर ट्रैवर्सल लागू करना पड़ा जो एक बीएफएस ऑर्डर में आउटपुट करता है। यह वास्तव में BFS नहीं है, लेकिन समान कार्य को पूरा करता है।

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;
}

2
अन्य दर्शकों के लिए: यह एक सरणी में एक पूर्ण पेड़ को लागू करने का एक उदाहरण है ; विशेष रूप से, @ जस्टिन एक प्री-ऑर्डर ट्रैवर्सल कर रहा है, जिसके दौरान वह उपयुक्त बीएफएस इंडेक्स में एक सरणी में नोड मान (बीएफएस ऑर्डर में) बचाता है। यह कॉल फ़ंक्शन को सरणी के माध्यम से रैखिक रूप से पुनरावृत्त करने की अनुमति देता है, बीएफएस ऑर्डर में प्रिंटिंग मान। इस सामान्य विवरण को देखें नोट: कॉलिंग फ़ंक्शन को गैर-पूर्ण पेड़ों के मामले को संभालना होगा।
बंकरडिव

1

आज्ञा देना शुरू करने के शीर्ष v

G को प्रश्न में ग्राफ होने दें

कतार का उपयोग किए बिना निम्नलिखित छद्म कोड है

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)

मुझे लगता है कि यह एक अनंत लूप में फंस सकता है - कोने को विज़िट के रूप में चिह्नित किया जा रहा है, लेकिन फिर से शाप देने से पहले उन्हें विज़िट-नेस के लिए कभी भी परीक्षण नहीं किया जाता है।

यह स्निपेट
बीएफएस के

1

एक द्विआधारी (या एन-एरी) पेड़ के लिए बीएफएस निम्नानुसार कतार के बिना पुनरावर्ती रूप से किया जा सकता है (जावा में यहां):

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;
    }
}

एक उदाहरण ट्रैवर्सल प्रिंटिंग नंबर 1-12 आरोही क्रम में:

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));
}

0
#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;
}

0

यहां एक जावास्क्रिप्ट कार्यान्वयन है जो डेप्थ फ़र्स्ट रिकर्सन के साथ चौड़ाई फर्स्ट ट्रैवर्सल बनाता है। मैं एक सरणी के अंदर, एक हैश के अंदर प्रत्येक नोड पर नोड मानों को संग्रहीत कर रहा हूं। यदि एक स्तर पहले से मौजूद है (हमारे पास टक्कर है), तो हम सिर्फ उस स्तर पर सरणी पर धक्का देते हैं। आप जावास्क्रिप्ट ऑब्जेक्ट के बजाय एक सरणी का उपयोग कर सकते हैं और साथ ही साथ हमारे स्तर संख्यात्मक हैं और सरणी सूचकांकों के रूप में काम कर सकते हैं। आप नोड्स, मान लौटा सकते हैं, लिंक की गई सूची में कनवर्ट कर सकते हैं, या जो भी आप चाहते हैं। मैं सिर्फ सादगी के लिए मान लौटा रहा हूं।

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 ] } */

यहाँ पुनरावृत्त दृष्टिकोण का उपयोग करके वास्तविक चौड़ाई फर्स्ट ट्रैवर्सल का एक उदाहरण है।

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

0

लूप और कतार का उपयोग किए बिना एक द्विदिश ग्राफ की चौड़ाई-पहले-खोज की पूरी तरह से पुनरावर्ती कार्यान्वयन के लिए मेरा कोड निम्नलिखित है।

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); } }


0

बाइनरी ट्री के लिए पुनरावर्ती चौड़ाई-प्रथम खोज एल्गोरिदम का सी # कार्यान्वयन।

बाइनरी ट्री डेटा विज़ुअलाइज़ेशन

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 })));
}

यदि आप चाहते हैं कि एल्गोरिथ्म न केवल बाइनरी-ट्री के साथ काम करे, बल्कि ग्राफ़ के साथ दो और अधिक नोड्स हो सकते हैं जो एक ही दूसरे नोड की ओर इशारा करते हैं तो आपको पहले से ही विजिट किए गए नोड्स की सूची को पकड़कर सेल्फ-साइक्लिंग से बचना होगा। कार्यान्वयन इस तरह लग सकता है।

ग्राफ़ डेटा विज़ुअलाइज़ेशन

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();
    });
}

0

मैंने सी ++ का उपयोग करके एक कार्यक्रम बनाया है जो संयुक्त और असमान ग्राफ में भी काम कर रहा है।

    #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;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.