Поиск в ширину (BFS) и поиск в глубину (DFS) для двоичных деревьев в Java
Поиск в ширину и поиск в глубину — это два метода обхода графов и деревьев. В этом руководстве мы сосредоточимся в основном на обходах BFS и DFS в деревьях.
Что такое поиск в глубину (DFS)?
Алгоритм начинается с корневого узла, а затем исследует каждую ветвь перед возвратом. Он реализован с помощью стеков. Часто при написании кода мы используем стеки рекурсии для возврата. Используя рекурсию, мы можем воспользоваться тем фактом, что левое и правое поддеревья также являются деревьями и имеют одни и те же свойства.
Для двоичных деревьев существует три типа обхода DFS.
- По порядку
- Предварительный заказ
- Постзаказ
Что такое поиск в ширину (BFS)?
Этот алгоритм также начинается с корневого узла, а затем посещает все узлы уровень за уровнем. Это означает, что после корня он проходит по всем прямым дочерним элементам корня. После обхода всех прямых потомков корня он переходит к их потомкам и так далее. Для реализации BFS мы используем очередь.
Для бинарных деревьев у нас есть обход порядка уровней, который следует за BFS.
Реализация BFS и DFS на Java
Пусть рассматриваемое дерево:
Структура класса TreeNode выглядит следующим образом:
static class TreeNode {
int data;
TreeNode left, right;
public TreeNode(int key) {
data = key;
left = right = null;
}
}
1. Обход предварительного заказа
При предварительном обходе бинарного дерева мы сначала обходим корень, затем левое поддерево и, наконец, правое поддерево. Мы делаем это рекурсивно, чтобы воспользоваться тем фактом, что левое и правое поддеревья также являются деревьями.
Алгоритм обхода предварительного заказа следующий:
- Обход корня.
- Вызов preorder() для левого поддерева.
- Вызов preorder() для правого поддерева.
Обход предварительного заказа дерева выше:
0 1 3 4 2
Java-код выглядит следующим образом:
static void preorder(TreeNode TreeNode) {
if (TreeNode == null)
return;
// Traverse root
System.out.print(TreeNode.item + "->");
// Traverse left
preorder(TreeNode.left);
// Traverse right
preorder(TreeNode.right);
}
2. Обход по порядку
Обход двоичного дерева по порядку сначала проходит через левое поддерево, затем корень и, наконец, правое поддерево.
Алгоритм обхода по порядку следующий:
- Вызов inorder() для левого поддерева.
- Обход корня.
- Вызовите inorder() для правого поддерева.
Порядок обхода дерева выше:
3 1 4 0 2
Java-код выглядит следующим образом:
static void inorder(TreeNode TreeNode) {
if (TreeNode == null)
return;
// Traverse left
inorder(TreeNode.left);
// Traverse root
System.out.print(TreeNode.item + "->");
// Traverse right
inorder(TreeNode.right);
}
3. Обход после заказа
Обход двоичного дерева в обратном порядке сначала проходит по левому поддереву, затем по правому поддереву и, наконец, по корню.
Алгоритм обхода после заказа следующий:
- Вызов postorder() для левого поддерева.
- Вызов postorder() для правого поддерева.
- Обход корня.
Пост-порядковый обход дерева выше:
3 4 1 2 0
Java-код выглядит следующим образом:
static void postorder(TreeNode TreeNode) {
if (TreeNode == null)
return;
// Traverse left
postorder(TreeNode.left);
// Traverse right
postorder(TreeNode.right);
// Traverse root
System.out.print(TreeNode.item + "->");
}
4. Обход по уровням
Обход по порядку уровней использует очередь для отслеживания посещаемых узлов. После посещения узла его потомки помещаются в очередь. Чтобы получить новый узел для обхода, мы удаляем элементы из очереди.
Алгоритм следующий:
- Инициализировать пустую очередь
- Начните с установки temp от имени пользователя root
- Запускать цикл до тех пор, пока очередь не станет пустой
- Печатать данные из временного файла.
- Поставить дочерние элементы temp в порядке слева и справа.
- Удалить узел из очереди и присвоить его значение переменной temp.
Обход по порядку уровней дерева выше:
0 1 2 3 4
Java-код выглядит следующим образом:
static void printLevelOrder(TreeNode root) { Queue<TreeNode> queue = new LinkedList<TreeNode>(); queue.add(root); while (!queue.isEmpty()) { TreeNode temp = queue.poll(); System.out.print(temp.data + " "); /*add left child to the queue */ if (temp.left != null) { queue.add(temp.left); } /*add right right child to the queue */ if (temp.right != null) { queue.add(temp.right); } } }
Полная реализация кода BFS и DFS на Java
Полный код Java приведен ниже:
package com.JournalDev; import java.util.LinkedList; import java.util.Queue; public class Main { static class TreeNode { int data; TreeNode left, right; public TreeNode(int key) { data = key; left = right = null; } } static void preorder(TreeNode TreeNode) { if (TreeNode == null) return; // Traverse root System.out.print(TreeNode.data + " "); // Traverse left preorder(TreeNode.left); // Traverse right preorder(TreeNode.right); } static void inorder(TreeNode TreeNode) { if (TreeNode == null) return; // Traverse left inorder(TreeNode.left); // Traverse root System.out.print(TreeNode.data + " "); // Traverse right inorder(TreeNode.right); } static void postorder(TreeNode TreeNode) { if (TreeNode == null) return; // Traverse left postorder(TreeNode.left); // Traverse right postorder(TreeNode.right); // Traverse root System.out.print(TreeNode.data + " "); } static void printLevelOrder(TreeNode root) { Queue<TreeNode> queue = new LinkedList<TreeNode>(); queue.add(root); while (!queue.isEmpty()) { TreeNode tempNode = queue.poll(); System.out.print(tempNode.data + " "); /*add left child to the queue */ if (tempNode.left != null) { queue.add(tempNode.left); } /*add right right child to the queue */ if (tempNode.right != null) { queue.add(tempNode.right); } } } public static void main(String args[]) { TreeNode root = new TreeNode(0); root.left = new TreeNode(1); root.right = new TreeNode(2); root.left.left = new TreeNode(3); root.left.right = new TreeNode(4); System.out.println("Inorder traversal"); inorder(root); System.out.println("\nPreorder traversal "); preorder(root); System.out.println("\nPostorder traversal"); postorder(root); System.out.println("\nLevelorder traversal"); printLevelOrder(root); } }
Output : Inorder traversal 3 1 4 0 2 Preorder traversal 0 1 3 4 2 Postorder traversal 3 4 1 2 0 Levelorder traversal 0 1 2 3 4
Заключение
Это руководство было посвящено обходам BFS и DFS в двоичных деревьях. Чтобы получить реализацию DFS на C++, обратитесь к этому руководству.