Нерекурсивный алгоритм первого поиска глубины - программирование

Нерекурсивный алгоритм первого поиска глубины

Я ищу алгоритм поиска нерекурсивной глубины первого недвоичного дерева. Любая помощь очень ценится.

4b9b3361

Ответ 1

ДФС:

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() удаляет и возвращает первый элемент в списке.

Ответ 2

Вы бы использовали stack, который содержит узлы, которые еще не были посещены:

stack.push(root)
while !stack.isEmpty() do
    node = stack.pop()
    for each node.childNodes do
        stack.push(stack)
    endfor
    // …
endwhile

Ответ 3

Если у вас есть указатели на родительские узлы, вы можете сделать это без дополнительной памяти.

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

Ответ 4

Использование стека для отслеживания ваших узлов

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)

}

Ответ 5

В то время как "использование стека" может работать как ответ на надуманный вопрос интервью, на самом деле он просто делает явно то, что рекурсивная программа делает за кулисами.

Рекурсия использует встроенный стек программ. Когда вы вызываете функцию, она подталкивает аргументы к функции в стек, и когда функция возвращает ее, она выдает стек программы.

Ответ 6

Реализация 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);
  }
}

Ответ 7

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

                }
            }

Общая логика: нажмите node (начиная с корня) в значения Stack, Pop() it и Print(). Затем, если у него есть дети (слева и справа), вставьте их в стек - сначала нажмите "Вперёд", чтобы вы сначала посетили левого ребенка (после посещения самой node). Когда стек пуст(), вы будете посещать все узлы в предварительном порядке.

Ответ 8

Предположим, вы хотите выполнить уведомление, когда каждый node в графике посещается. Простая рекурсивная реализация:

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
}

Хорошо, теперь вам нужна реализация на основе стека, потому что ваш пример не работает. Сложные графики могут, например, привести к тому, что это приведет к удалению стека вашей программы, и вам нужно реализовать нерекурсивную версию. Самая большая проблема заключается в том, чтобы знать, когда выдать уведомление.

Следующий псевдокод работает (сочетание Java и С++ для удобочитаемости):

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. Запустите собственную реализацию DFS и порядок, в котором следует посещать узлы, должен быть: w, t, v, s Неуклюжая реализация DFS может сначала уведомить t, а это означает ошибку. Рекурсивная реализация DFS всегда будет достигать последней.

Ответ 9

Нерекурсивная DFS с использованием генераторов ES6

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

Он отклоняется от типичной нерекурсивной DFS, чтобы легко обнаружить, когда обработаны все доступные потомки данных node и для поддержания текущего пути в списке/стеке.

Ответ 10

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

Ответ 11

Вы можете использовать стек. Я реализовал графики с матрицей смежности:

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

Ответ 12

Иерархия DFS в Java:

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

Ответ 13

Используя Stack, выполните следующие действия: Нажмите первую вершину в стеке, затем

  • Если возможно, посетите соседнюю невидимую вершину, отметьте ее, и надавите на стек.
  • Если вы не можете выполнить шаг 1, то, если это возможно, вытащите вершину с стек.
  • Если вы не можете выполнить шаг 1 или шаг 2, вы сделали.

Здесь программа Java выполняет следующие шаги:

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

Ответ 14

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