Найдите kth самый маленький элемент в дереве двоичного поиска Оптимальным способом

Я должен найти kth самый маленький элемент в дереве двоичного поиска, не используя статической / глобальной переменной. Как достигнуть его эффективно? Решение, которое я знаю, делает операцию в O (n), худший случай, так как я планирую сделать inorder обход всего дерева. Но в глубине души я чувствую, что не использую свойство BST здесь. Мое допускаемое решение правильно или является там лучшим доступным?

110
задан bragboy 16 May 2012 в 19:07
поделиться

6 ответов

Вот лишь краткое описание идеи:

В BST левое поддерево узла T содержит только элементы, меньшие, чем значение хранится в T . Если k меньше количества элементов в левом поддереве, k -й наименьший элемент должен принадлежать левому поддереву. В противном случае, если k больше, то самый маленький элемент k находится в правом поддереве.

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

Теперь предположим, что мы находимся в узле T:

  1. Если k == num_elements (левое поддерево T) , то ответ, который мы ищем, - это значение в узле T .
  2. Если k> num_elements (левое поддерево T) , то, очевидно, мы можем игнорировать левое поддерево, потому что эти элементы также будут меньше k -го наименьшего.Итак, мы сводим задачу к поиску k - num_elements (левое поддерево T) наименьшего элемента правого поддерева.
  3. Если k , то самый маленький k -й наименьший находится где-то в левом поддереве, поэтому мы сводим проблему к поиску k -й наименьший элемент в левом поддереве.

Анализ сложности:

Это занимает O (глубина узла) времени, что составляет O (log n) в худшем случае на сбалансированной BST или ] O (log n) в среднем для случайного BST.

BST требует хранения O (n) , а для хранения информации о количестве элементов требуется еще O (n) . Все операции BST занимают O (глубина узла) времени, и требуется O (глубина узла) дополнительного времени для поддержания информации о «количестве элементов» для вставки, удаления или поворота. узлов. Следовательно, хранение информации о количестве элементов в левом поддереве сохраняет пространственную и временную сложность BST.

168
ответ дан 24 November 2019 в 03:11
поделиться

Учитывая простое двоичное дерево поиска, все, что вы можете сделать, - это начать с наименьшего и подняться вверх, чтобы найти нужный узел.

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

4
ответ дан 24 November 2019 в 03:11
поделиться
public int ReturnKthSmallestElement1(int k)
    {
        Node node = Root;

        int count = k;

        int sizeOfLeftSubtree = 0;

        while(node != null)
        {

            sizeOfLeftSubtree = node.SizeOfLeftSubtree();

            if (sizeOfLeftSubtree + 1 == count)
                return node.Value;
            else if (sizeOfLeftSubtree < count)
            {
                node = node.Right;
                count -= sizeOfLeftSubtree+1;
            }
            else
            {
                node = node.Left;
            }
        }

        return -1;
    }

это моя реализация на C #, основанная на алгоритме выше, я просто подумал, что выложу его, чтобы люди могли лучше понять, что он работает для меня

спасибо IVlad

13
ответ дан 24 November 2019 в 03:11
поделиться

Для не сбалансированного дерева поиска требуется O(n).

Для сбалансированного дерева поиска требуется O(k + log n) в худшем случае, но только O(k) в амортизированном смысле.

Наличие и управление дополнительным целым числом для каждого узла: размером поддерева дает O(log n) временную сложность. Такое сбалансированное дерево поиска обычно называют RankTree.

В целом, существуют решения (основанные не на дереве).

С уважением.

3
ответ дан 24 November 2019 в 03:11
поделиться

Это то, что я подумал, и это работает. Он будет работать в o (log n)

public static int FindkThSmallestElemet(Node root, int k)
    {
        int count = 0;
        Node current = root;

        while (current != null)
        {
            count++;
            current = current.left;
        }
        current = root;

        while (current != null)
        {
            if (count == k)
                return current.data;
            else
            {
                current = current.left;
                count--;
            }
        }

        return -1;


    } // end of function FindkThSmallestElemet
0
ответ дан 24 November 2019 в 03:11
поделиться

Для двоичного дерева поиска обход по порядку вернет элементы ... по порядку.

Просто выполните обход в порядке и остановитесь после обхода k элементов.

O (1) для постоянных значений k.

-5
ответ дан 24 November 2019 в 03:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: