मैं गैर-बाइनरी ट्री के लिए एक गैर-पुनरावर्ती गहराई पहले खोज एल्गोरिथ्म की तलाश कर रहा हूं। किसी भी प्रकार के मदद की बहुत सराहना की जाएगी।
मैं गैर-बाइनरी ट्री के लिए एक गैर-पुनरावर्ती गहराई पहले खोज एल्गोरिथ्म की तलाश कर रहा हूं। किसी भी प्रकार के मदद की बहुत सराहना की जाएगी।
जवाबों:
डीएफएस:
list nodes_to_visit = {root};
while( nodes_to_visit isn't empty ) {
currentnode = nodes_to_visit.take_first();
nodes_to_visit.prepend( currentnode.children );
//do something
}
BFS:
list nodes_to_visit = {root};
while( nodes_to_visit isn't empty ) {
currentnode = nodes_to_visit.take_first();
nodes_to_visit.append( currentnode.children );
//do something
}
दोनों की समरूपता काफी शांत है।
अद्यतन: जैसा कि बताया गया है, take_first()
सूची में पहला तत्व निकालता है और वापस करता है।
.first()
फ़ंक्शन सूची से तत्व को भी हटा देता है। जैसे shift()
कई भाषाओं में। pop()
यह भी काम करता है, और बाएं-दाएं के बजाय दाएं से बाएं क्रम में बच्चे के नोड्स लौटाता है।
gray(1st)->gray(2nd)->gray(3rd)->blacken(3rd)->blacken(2nd)->blacken(1st)
। लेकिन आपका कोड उत्पादन करता है gray(1st)->gray(2nd)->gray(3rd)->blacken(2nd)->blacken(3rd)->blacken(1st)
:।
आप एक स्टैक का उपयोग करेंगे जो उन नोड्स को रखता है जो अभी तक नहीं गए थे:
stack.push(root)
while !stack.isEmpty() do
node = stack.pop()
for each node.childNodes do
stack.push(stack)
endfor
// …
endwhile
if (nodes are not marked)
जज को जोड़ते हैं कि क्या इसे स्टैक पर धकेल दिया जाना है। क्या वह काम कर सकता है?
doing cycles
? मुझे लगता है कि मैं सिर्फ डीएफएस का आदेश चाहता हूं। यह सही है या नहीं, धन्यवाद।
for each node.childNodes.reverse() do stack.push(stack) endfor
) में धकेलना होगा । यह भी शायद आप चाहते हैं। अच्छा स्पष्टीकरण कि ऐसा क्यों है इस वीडियो में है: youtube.com/watch?v=cZPXfl_tUkA endfor
यदि आपके पास मूल नोड्स के संकेत हैं, तो आप इसे अतिरिक्त मेमोरी के बिना कर सकते हैं।
def dfs(root):
node = root
while True:
visit(node)
if node.first_child:
node = node.first_child # walk down
else:
while not node.next_sibling:
if node is root:
return
node = node.parent # walk up ...
node = node.next_sibling # ... and right
ध्यान दें कि यदि बच्चे के नोड्स को सिबलिंग पॉइंटर्स के बजाय एक सरणी के रूप में संग्रहीत किया जाता है, तो अगले सिबलिंग को निम्न प्रकार से पाया जा सकता है:
def next_sibling(node):
try:
i = node.parent.child_nodes.index(node)
return node.parent.child_nodes[i+1]
except (IndexError, AttributeError):
return None
while not node.next_sibling or node is root:
।
अपने नोड्स को ट्रैक करने के लिए एक स्टैक का उपयोग करें
Stack<Node> s;
s.prepend(tree.head);
while(!s.empty) {
Node n = s.poll_front // gets first node
// do something with q?
for each child of n: s.prepend(child)
}
हालांकि "स्टैक का उपयोग करें" वास्तव में, साक्षात्कार के प्रश्न से संबंधित प्रश्न के उत्तर के रूप में काम कर सकता है, यह सिर्फ स्पष्ट रूप से कर रहा है कि एक पुनरावर्ती कार्यक्रम पर्दे के पीछे क्या करता है।
रिकर्सन प्रोग्राम में निर्मित स्टैक का उपयोग करता है। जब आप किसी फ़ंक्शन को कॉल करते हैं, तो यह फ़ंक्शन के तर्कों को स्टैक पर धकेलता है और जब फ़ंक्शन वापस आता है तो प्रोग्राम स्टैक को पॉप अप करके ऐसा करता है।
एक ES6 कार्यान्वयन biziclops महान जवाब पर आधारित है:
root = {
text: "root",
children: [{
text: "c1",
children: [{
text: "c11"
}, {
text: "c12"
}]
}, {
text: "c2",
children: [{
text: "c21"
}, {
text: "c22"
}]
}, ]
}
console.log("DFS:")
DFS(root, node => node.children, node => console.log(node.text));
console.log("BFS:")
BFS(root, node => node.children, node => console.log(node.text));
function BFS(root, getChildren, visit) {
let nodesToVisit = [root];
while (nodesToVisit.length > 0) {
const currentNode = nodesToVisit.shift();
nodesToVisit = [
...nodesToVisit,
...(getChildren(currentNode) || []),
];
visit(currentNode);
}
}
function DFS(root, getChildren, visit) {
let nodesToVisit = [root];
while (nodesToVisit.length > 0) {
const currentNode = nodesToVisit.shift();
nodesToVisit = [
...(getChildren(currentNode) || []),
...nodesToVisit,
];
visit(currentNode);
}
}
PreOrderTraversal is same as DFS in binary tree. You can do the same recursion
taking care of Stack as below.
public void IterativePreOrder(Tree root)
{
if (root == null)
return;
Stack s<Tree> = new Stack<Tree>();
s.Push(root);
while (s.Count != 0)
{
Tree b = s.Pop();
Console.Write(b.Data + " ");
if (b.Right != null)
s.Push(b.Right);
if (b.Left != null)
s.Push(b.Left);
}
}
सामान्य तर्क है, एक नोड (रूट से शुरू) को स्टैक, पॉप () और इसे (प्रिंट) मान में धकेलें। फिर अगर इसमें बच्चे (बाएं और दाएं) हैं, तो उन्हें स्टैक में धकेल दें - दाएं को पहले धक्का दें ताकि आप पहले बाएं बच्चे पर जाएँ (नोड पर जाने के बाद)। जब स्टैक खाली होता है () आप प्री-ऑर्डर में सभी नोड्स पर गए होंगे।
ईएस 6 जनरेटर का उपयोग करके गैर-पुनरावर्ती डीएफएस
class Node {
constructor(name, childNodes) {
this.name = name;
this.childNodes = childNodes;
this.visited = false;
}
}
function *dfs(s) {
let stack = [];
stack.push(s);
stackLoop: while (stack.length) {
let u = stack[stack.length - 1]; // peek
if (!u.visited) {
u.visited = true; // grey - visited
yield u;
}
for (let v of u.childNodes) {
if (!v.visited) {
stack.push(v);
continue stackLoop;
}
}
stack.pop(); // black - all reachable descendants were processed
}
}
यह विशिष्ट गैर-पुनरावर्ती डीएफएस से आसानी से पता लगाता है, जब दिए गए नोड के सभी पहुंच योग्य वंशजों को संसाधित किया गया था और सूची / स्टैक में वर्तमान पथ को बनाए रखने के लिए।
मान लीजिए कि आप किसी नोटिफिकेशन को निष्पादित करना चाहते हैं जब ग्राफ़ में प्रत्येक नोड का दौरा किया जाता है। सरल पुनरावर्ती कार्यान्वयन है:
void DFSRecursive(Node n, Set<Node> visited) {
visited.add(n);
for (Node x : neighbors_of(n)) { // iterate over all neighbors
if (!visited.contains(x)) {
DFSRecursive(x, visited);
}
}
OnVisit(n); // callback to say node is finally visited, after all its non-visited neighbors
}
ठीक है, अब आप एक स्टैक-आधारित कार्यान्वयन चाहते हैं क्योंकि आपका उदाहरण काम नहीं करता है। उदाहरण के लिए जटिल रेखांकन आपके कार्यक्रम के ढेर को उड़ाने का कारण बन सकता है और आपको गैर-पुनरावर्ती संस्करण को लागू करना होगा। सबसे बड़ा मुद्दा यह जानना है कि अधिसूचना कब जारी की जाए।
निम्नलिखित छद्म कोड काम करता है (पठनीयता के लिए जावा और सी ++ का मिश्रण):
void DFS(Node root) {
Set<Node> visited;
Set<Node> toNotify; // nodes we want to notify
Stack<Node> stack;
stack.add(root);
toNotify.add(root); // we won't pop nodes from this until DFS is done
while (!stack.empty()) {
Node current = stack.pop();
visited.add(current);
for (Node x : neighbors_of(current)) {
if (!visited.contains(x)) {
stack.add(x);
toNotify.add(x);
}
}
}
// Now issue notifications. toNotifyStack might contain duplicates (will never
// happen in a tree but easily happens in a graph)
Set<Node> notified;
while (!toNotify.empty()) {
Node n = toNotify.pop();
if (!toNotify.contains(n)) {
OnVisit(n); // issue callback
toNotify.add(n);
}
}
यह जटिल दिखता है, लेकिन अधिसूचना जारी करने के लिए आवश्यक अतिरिक्त तर्क मौजूद है क्योंकि आपको यात्रा के रिवर्स ऑर्डर में सूचित करने की आवश्यकता है - DFS रूट पर शुरू होता है, लेकिन BFS के विपरीत इसे अंतिम रूप से सूचित करता है, जिसे लागू करना बहुत सरल है।
किक्स के लिए, निम्नलिखित ग्राफ का प्रयास करें: नोड्स s, t, v और w हैं। निर्देशित किनारे हैं: s-> t, s-> v, t-> w, v-> w, और v-> t। डीएफएस के अपने स्वयं के कार्यान्वयन को चलाएं और जिस क्रम में नोड्स का दौरा किया जाना चाहिए वह होना चाहिए: डब्ल्यू, टी, वी, एस डीएफएस का अनाड़ी कार्यान्वयन शायद पहले टी को सूचित करेगा और यह एक बग को इंगित करता है। डीएफएस का पुनरावर्ती कार्यान्वयन हमेशा अंतिम तक पहुंच जाएगा।
स्टैक के बिना पूरा उदाहरण काम कोड,:
import java.util.*;
class Graph {
private List<List<Integer>> adj;
Graph(int numOfVertices) {
this.adj = new ArrayList<>();
for (int i = 0; i < numOfVertices; ++i)
adj.add(i, new ArrayList<>());
}
void addEdge(int v, int w) {
adj.get(v).add(w); // Add w to v's list.
}
void DFS(int v) {
int nodesToVisitIndex = 0;
List<Integer> nodesToVisit = new ArrayList<>();
nodesToVisit.add(v);
while (nodesToVisitIndex < nodesToVisit.size()) {
Integer nextChild= nodesToVisit.get(nodesToVisitIndex++);// get the node and mark it as visited node by inc the index over the element.
for (Integer s : adj.get(nextChild)) {
if (!nodesToVisit.contains(s)) {
nodesToVisit.add(nodesToVisitIndex, s);// add the node to the HEAD of the unvisited nodes list.
}
}
System.out.println(nextChild);
}
}
void BFS(int v) {
int nodesToVisitIndex = 0;
List<Integer> nodesToVisit = new ArrayList<>();
nodesToVisit.add(v);
while (nodesToVisitIndex < nodesToVisit.size()) {
Integer nextChild= nodesToVisit.get(nodesToVisitIndex++);// get the node and mark it as visited node by inc the index over the element.
for (Integer s : adj.get(nextChild)) {
if (!nodesToVisit.contains(s)) {
nodesToVisit.add(s);// add the node to the END of the unvisited node list.
}
}
System.out.println(nextChild);
}
}
public static void main(String args[]) {
Graph g = new Graph(5);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);
g.addEdge(3, 1);
g.addEdge(3, 4);
System.out.println("Breadth First Traversal- starting from vertex 2:");
g.BFS(2);
System.out.println("Depth First Traversal- starting from vertex 2:");
g.DFS(2);
}}
आउटपुट: चौड़ाई प्रथम ट्रावर्सल- वर्टेक्स २ से शुरू: २ ० ३ ४ ४ डेप्थ फर्स्ट ट्रावर्सल- वर्टेक्स २ से शुरू: २ ३ ४ १ ०
आप एक स्टैक का उपयोग कर सकते हैं। मैंने आसन्न मैट्रिक्स के साथ रेखांकन लागू किया:
void DFS(int current){
for(int i=1; i<N; i++) visit_table[i]=false;
myStack.push(current);
cout << current << " ";
while(!myStack.empty()){
current = myStack.top();
for(int i=0; i<N; i++){
if(AdjMatrix[current][i] == 1){
if(visit_table[i] == false){
myStack.push(i);
visit_table[i] = true;
cout << i << " ";
}
break;
}
else if(!myStack.empty())
myStack.pop();
}
}
}
जावा में DFS पुनरावृत्ति:
//DFS: Iterative
private Boolean DFSIterative(Node root, int target) {
if (root == null)
return false;
Stack<Node> _stack = new Stack<Node>();
_stack.push(root);
while (_stack.size() > 0) {
Node temp = _stack.peek();
if (temp.data == target)
return true;
if (temp.left != null)
_stack.push(temp.left);
else if (temp.right != null)
_stack.push(temp.right);
else
_stack.pop();
}
return false;
}
http://www.youtube.com/watch?v=zLZhSSXAwxI
बस इस वीडियो को देखा और कार्यान्वयन के साथ बाहर आया। मुझे समझना आसान लगता है। कृपया इसकी आलोचना करें।
visited_node={root}
stack.push(root)
while(!stack.empty){
unvisited_node = get_unvisited_adj_nodes(stack.top());
If (unvisited_node!=null){
stack.push(unvisited_node);
visited_node+=unvisited_node;
}
else
stack.pop()
}
उपयोग करने के लिए Stack
, यहाँ निम्नलिखित चरणों का पालन किया गया है: स्टैक पर पहले शीर्ष को पुश करें, फिर
उपरोक्त चरणों का पालन जावा प्रोग्राम है:
public void searchDepthFirst() {
// begin at vertex 0
vertexList[0].wasVisited = true;
displayVertex(0);
stack.push(0);
while (!stack.isEmpty()) {
int adjacentVertex = getAdjacentUnvisitedVertex(stack.peek());
// if no such vertex
if (adjacentVertex == -1) {
stack.pop();
} else {
vertexList[adjacentVertex].wasVisited = true;
// Do something
stack.push(adjacentVertex);
}
}
// stack is empty, so we're done, reset flags
for (int j = 0; j < nVerts; j++)
vertexList[j].wasVisited = false;
}
Stack<Node> stack = new Stack<>();
stack.add(root);
while (!stack.isEmpty()) {
Node node = stack.pop();
System.out.print(node.getData() + " ");
Node right = node.getRight();
if (right != null) {
stack.push(right);
}
Node left = node.getLeft();
if (left != null) {
stack.push(left);
}
}
@ Biziclop के उत्तर के आधार पर छद्म कोड:
getNode(id)
औरgetChildren(id)
N
नोट: मैं 1, नहीं 0 से सरणी-अनुक्रमण का उपयोग करता हूं।
चौड़ाई-पहले
S = Array(N)
S[1] = 1; // root id
cur = 1;
last = 1
while cur <= last
id = S[cur]
node = getNode(id)
children = getChildren(id)
n = length(children)
for i = 1..n
S[ last+i ] = children[i]
end
last = last+n
cur = cur+1
visit(node)
end
गहराई-प्रथम
S = Array(N)
S[1] = 1; // root id
cur = 1;
while cur > 0
id = S[cur]
node = getNode(id)
children = getChildren(id)
n = length(children)
for i = 1..n
// assuming children are given left-to-right
S[ cur+i-1 ] = children[ n-i+1 ]
// otherwise
// S[ cur+i-1 ] = children[i]
end
cur = cur+n-1
visit(node)
end
यहाँ एक जावा प्रोग्राम का लिंक दिया गया है, जो डीएसएफ को रीक्रसिव और नॉन-रीक्रसिव दोनों तरीकों से दिखाता है और डिस्कवरी और फिनिश टाइम की गणना भी करता है, लेकिन कोई एज लैलालिंग नहीं।
public void DFSIterative() {
Reset();
Stack<Vertex> s = new Stack<>();
for (Vertex v : vertices.values()) {
if (!v.visited) {
v.d = ++time;
v.visited = true;
s.push(v);
while (!s.isEmpty()) {
Vertex u = s.peek();
s.pop();
boolean bFinished = true;
for (Vertex w : u.adj) {
if (!w.visited) {
w.visited = true;
w.d = ++time;
w.p = u;
s.push(w);
bFinished = false;
break;
}
}
if (bFinished) {
u.f = ++time;
if (u.p != null)
s.push(u.p);
}
}
}
}
}
पूर्ण स्रोत यहाँ ।
बस समाधानों की लंबी सूची में मेरे अजगर कार्यान्वयन को जोड़ना चाहता था। इस गैर-पुनरावर्ती एल्गोरिथ्म में खोज और समाप्त होने वाली घटनाएं हैं।
worklist = [root_node]
visited = set()
while worklist:
node = worklist[-1]
if node in visited:
# Node is finished
worklist.pop()
else:
# Node is discovered
visited.add(node)
for child in node.children:
worklist.append(child)