#c #binary-search-tree
#c #двоичное дерево поиска
Вопрос:
Этот вопрос был задан мне в интервью:
допустим, у нас есть вышеупомянутое двоичное дерево, как я могу создать вывод, подобный приведенному ниже
2 7 5 2 6 9 5 11 4
я ответил, что, возможно, у нас может быть переменная level count и печатать все элементы последовательно, проверяя переменную level count каждого узла.
возможно, я был неправ.
кто-нибудь может дать какие-либо идеи относительно того, как мы можем этого добиться?
Комментарии:
1. простое представление BT в порядке уровней
2. смотрите вширь-first_Traversal
3. Ваши теги предполагают, что это вопрос о бинарных деревьях поиска, но это не пример одного из них. Это не важно; обычный алгоритм работает одинаково для всех типов деревьев.
Ответ №1:
Вам нужно сначала выполнить обход дерева по ширине. Здесь это описано следующим образом:
Обход в ширину: сначала в глубину — не единственный способ обхода элементов дерева. Другой способ — просмотреть их по уровням.
Например, каждый элемент существует на определенном уровне (или глубине) в дереве:
tree
----
j <-- level 0
/
f k <-- level 1
/
a h z <-- level 2
d <-- level 3
людям нравится нумеровать вещи, начиная
с 0.)Итак, если мы хотим просматривать элементы по уровням (и слева направо, как обычно), мы должны начать с уровня 0 с j, затем перейти к уровню 1 для f и k, затем перейти к уровню 2 для a, h и z и, наконец, перейти к уровню 3 для d .
Этот поэтапный обход называется обходом в ширину, потому что мы исследуем ширину, то есть полную ширину дерева на данном уровне, прежде чем углубляться.
Комментарии:
1. есть ли у вас какой-либо ресурс, объясняющий обход в ширину?
Ответ №2:
Обход в вашем вопросе называется a, level-order traversal
и вот как это делается (я нашел очень простой / чистый фрагмент кода).
В основном вы используете очередь, и порядок операций будет выглядеть примерно так:
enqueue F
dequeue F
enqueue B G
dequeue B
enqueue A D
dequeue G
enqueue I
dequeue A
dequeue D
enqueue C E
dequeue I
enqueue H
dequeue C
dequeue E
dequeue H
Для этого дерева (прямо из Википедии):
Ответ №3:
Термин для этого — обход порядка уровней. В Википедии описан алгоритм для этого с использованием очереди:
levelorder(root)
q = empty queue
q.enqueue(root)
while not q.empty do
node := q.dequeue()
visit(node)
if node.left ≠ null
q.enqueue(node.left)
if node.right ≠ null
q.enqueue(node.right)
Ответ №4:
BFS:
std::queue<Node const *> q;
q.push(amp;root);
while (!q.empty()) {
Node const *n = q.front();
q.pop();
std::cout << n->data << std::endl;
if (n->left)
q.push(n->left);
if (n->right)
q.push(n->right);
}
Итеративное углубление также будет работать и сэкономит использование памяти, но за счет вычислительного времени.
Ответ №5:
Если мы сможем получить следующий элемент на том же уровне, мы закончили. Согласно нашим предварительным знаниям, мы можем получить доступ к этим элементам, используя обход в ширину.
Теперь единственная проблема заключается в том, как проверить, находимся ли мы в конечном элементе на любом уровне. По этой причине мы должны добавлять разделитель (в данном случае NULL) для обозначения конца уровня.
Алгоритм: 1. Поместите root в очередь.
2. Поместите NULL в очередь.
3. Пока очередь не пуста
4. x = выборка первого элемента из очереди
5. Если x не равно НУЛЮ
6. x->rpeer <= верхний элемент очереди.
7. поместите левый и правый дочерние элементы x в очередь
8. else
9. если очередь не пуста
10. поместите NULL в очередь
11. завершите, если
12. завершите, пока
13. верните
#include <queue>
void print(tree* root)
{
queue<tree*> que;
if (!root)
return;
tree *tmp, *l, *r;
que.push(root);
que.push(NULL);
while( !que.empty() )
{
tmp = que.front();
que.pop();
if(tmp != NULL)
{
cout << tmp=>val; //print value
l = tmp->left;
r = tmp->right;
if(l) que.push(l);
if(r) que.push(r);
}
else
{
if (!que.empty())
que.push(NULL);
}
}
return;
}
Ответ №6:
Я бы использовал коллекцию, например std::list
, для хранения всех элементов текущего печатного уровня:
- Соберите указатели на все узлы текущего уровня в контейнере
- Выведите узлы, перечисленные в контейнере
- Создайте новый контейнер, добавьте подузлы всех узлов в контейнере
- Замените старый контейнер новым контейнером
- повторяйте, пока контейнер не опустеет
Ответ №7:
в качестве примера того, что вы можете сделать на собеседовании, если вы не помните / не знаете «официального» алгоритма, моей первой идеей было — обойти дерево в обычном предварительном заказе, перетаскивая счетчик уровней, поддерживая вектор связанных списков указателей на узлы для каждого уровня, например
levels[level].push_back(amp;node);
и в конце выведите список каждого уровня.