Ben ikili olmayan bir ağaç için özyinelemeli olmayan derinlik ilk arama algoritması arıyorum. Herhangi bir yardım çok takdir edilmektedir.
Ben ikili olmayan bir ağaç için özyinelemeli olmayan derinlik ilk arama algoritması arıyorum. Herhangi bir yardım çok takdir edilmektedir.
Yanıtlar:
DFS:
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
}
İkisinin simetrisi oldukça havalı.
Güncelleme: Belirtildiği gibi take_first()
, listedeki ilk öğeyi kaldırır ve döndürür.
.first()
işlev ayrıca öğeyi listeden kaldırır. İster shift()
birçok dilde. pop()
ayrıca çalışır ve alt düğümleri soldan sağa yerine sağdan sola doğru döndürür.
gray(1st)->gray(2nd)->gray(3rd)->blacken(3rd)->blacken(2nd)->blacken(1st)
. Ancak kodunuz üretir: gray(1st)->gray(2nd)->gray(3rd)->blacken(2nd)->blacken(3rd)->blacken(1st)
.
Henüz ziyaret edilmemiş düğümleri tutan bir yığın kullanırsınız :
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)
ve yığına itilmeye uygun olup olmadığına karar vermek için a eklemek . Bu işe yarayabilir mi?
doing cycles
? Bence sadece DFS sırasını istiyorum. Bu doğru mu değil mi, teşekkür ederim.
for each node.childNodes.reverse() do stack.push(stack) endfor
) itmeniz gerektiğini belirtmek gerekir . Muhtemelen istediğiniz şey de budur. Neden bu videoda olduğu gibi güzel bir açıklama: youtube.com/watch?v=cZPXfl_tUkA endfor
Üst düğümlere işaretçileriniz varsa, bunu ek bellek olmadan yapabilirsiniz.
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
Alt düğümlerin kardeş işaretçiler yerine bir dizi olarak depolanması durumunda, bir sonraki kardeşin şu şekilde bulunabileceğini unutmayın:
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:
.
Düğümlerinizi izlemek için bir yığın kullanın
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)
}
"Bir yığın kullanmak" iken olabilir gerçekte, yapmacık mülakat sorusu için çalışmak, sadece bir özyinelemeli programı perde arkasında ne açıkça yapıyor.
Özyineleme yerleşik programları kullanır. Bir işlevi çağırdığınızda, bağımsız değişkenleri işleve yığının üzerine iter ve işlev döndüğünde program yığınını açarak bunu yapar.
Biziclops büyük cevaba dayanan bir ES6 uygulaması:
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);
}
}
Genel mantık, bir düğümü (kökten başlayarak) Yığına, Pop () ve Print () değerine itmektir. Daha sonra çocukları varsa (sol ve sağ) onları yığına itin - önce Sol çocuğu ziyaret etmek için önce (düğümü ziyaret ettikten sonra) Sağa basın. Yığın boşken () Ön Siparişteki tüm düğümleri ziyaret etmiş olacaksınız.
ES6 jeneratörlerini kullanan özyinelemesiz DFS
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
}
}
Belirli bir düğümün tüm ulaşılabilir torunları işlendiğinde kolayca algılamak ve liste / yığındaki geçerli yolu korumak için tipik özyinelemeli olmayan DFS'den sapar .
Bir grafikteki her düğüm ziyaret edildiğinde bir bildirim yürütmek istediğinizi varsayalım. Basit özyinelemeli uygulama:
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
}
Tamam, şimdi örneğiniz çalışmadığından yığın tabanlı bir uygulama istiyorsunuz. Karmaşık grafikler, bunun programınızın yığınını üflemesine neden olabilir ve özyinelemeli olmayan bir sürüm uygulamanız gerekir. En büyük sorun ne zaman bildirim yapılacağını bilmek.
Aşağıdaki sözde kod çalışır (okunabilirlik için Java ve C ++ karışımı):
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);
}
}
Karmaşık görünüyor, ancak bildirimleri yayınlamak için gereken ekstra mantık var çünkü ziyaretin tersini bildirmeniz gerekiyor - DFS kökten başlıyor, ancak uygulanması çok basit olan BFS'nin aksine son bildiriyor.
Tekmeler için aşağıdaki grafiği deneyin: düğümler s, t, v ve w'dir. yönlendirilmiş kenarlar şunlardır: s-> t, s-> v, t-> w, v-> w ve v-> t. Kendi DFS uygulamanızı çalıştırın ve düğümlerin ziyaret edilme sırası şu olmalıdır: w, t, v, s DFS'nin beceriksiz bir uygulaması, önce t'yi bildirebilir ve bu bir hatayı gösterir. Yinelenen bir DFS uygulaması her zaman en son w'ye ulaşacaktır.
TAM örnek Yığın olmadan ÇALIŞMA kodu:
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);
}}
çıktı: Genişlik İlk Geçiş - köşe 2'den başlayarak: 2 0 3 1 4 Derinlik İlk Geçiş - köşe 2'den başlayarak: 2 3 4 1 0
Bir yığın kullanabilirsiniz. Bitişiklik Matrisi ile grafikler uyguladım:
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();
}
}
}
Java'da DFS yinelemesi:
//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
Sadece bu videoyu izledim ve uygulamaya koyulduk. Anlamak kolay görünüyor. Lütfen bunu eleştir.
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()
}
Kullanarak Stack
, izlenmesi gereken adımlar şunlardır: Yığındaki ilk tepe noktasını itin,
Yukarıdaki adımları izleyen Java programı şöyledir:
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'un cevabına dayanan sahte kod:
getNode(id)
vegetChildren(id)
N
Not: 0 değil, 1 dizini dizin oluşturma kullanın.
Genişlik-ilk
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
Derinlik öncelikli
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
Burada, hem yinelemeli hem de yinelemesiz yöntemleri izleyen ve aynı zamanda keşif ve bitiş zamanını hesaplayan , ancak kenar boşluğu olmayan DFS'yi gösteren bir java programı bağlantısı .
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);
}
}
}
}
}
Tam kaynak burada .
Python uygulamamı uzun çözümler listesine eklemek istedim. Bu özyinelemeli olmayan algoritmanın keşif ve bitmiş olayları vardır.
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)