Странные результаты при черчении (Cormen) Красно-черная вставка дерева - PullRequest
5 голосов
/ 02 марта 2012

Я реализовал в красно-черных деревьях в Python в соответствии с псевдокодом в Introduction to Algorithms.

Кормена. Я хотел увидеть своими глазами, что мой insert действительно O(logn), поэтому я построил графиквремя, необходимое для вставки n=1, 10, 20, ..., 5000 узлов в дерево.

Это результат:

enter image description here

ось x равна nось y - это время, которое заняло миллисекунд .

Для меня график выглядит более линейным, чем логарифмическим.Чем это можно объяснить?

Ответы [ 3 ]

4 голосов
/ 02 марта 2012

Хорошо, поэтому график отображает измерение стоимости вставки n элементов в ваше дерево, где ось x - это количество элементов, которые мы вставили, а ось y - общее время.

Давайте назовем функцию, которая суммирует время, необходимое для вставки n элементов в дерево f(n).

Тогда мы можем получить приблизительное представление о том, как может выглядеть f:

f(1) < k*log(1)                 for some constant k.

f(2) < k*log(1) + k*log(2)      for some constant k

...

f(n) < k * [log(1) + log(2) + ... + log(n)]   for some constant k.

Из-за того, как работают журналы, мы можем свернуть log(1) + ... + log(n):

f(n) < k * [log(1*2*3*...*n)]     for some constant k

f(n) < k * log(n!)                for some constant k

Мы можем взглянуть на Википедию, чтобы увидеть график того, как выглядит log(n!). Посмотрите на график в статье. Должно выглядеть довольно знакомым для вас. :)

То есть я думаю, что вы сделали это случайно:

for n in (5000, 50000, 500000):
    startTime = ...
    ## .. make a fresh tree
    ## insert n elements into the tree
    stopTime = ...
    ## record the tuple (n, stopTime - startTime) for plotting

и вычерчивает общее время построения дерева размера n, а не отдельные затраты на вставку одного элемента в дерево размера n:

for n in range(50000):
    startTime = ...
    ## insert an element into the tree
    stopTime = ...
    ## record the tuple (n, stopTime - startTime) for plotting

Крис Тейлор отмечает в комментариях, что если вы построите график f(n)/n, вы увидите график журнала. Это потому, что довольно точное приближение к log(n!) равно n*log(n) (см. Страницу Википедии). Итак, мы можем вернуться к нашей границе:

f(n) < k * log(n!)                for some constant k

и получите:

f(n) < k * n * log(n)             for some constant k

И теперь должно быть проще понять, что если вы поделите f(n) на n, ваш график будет ограничен сверху формой логарифма.

3 голосов
/ 02 марта 2012

5000 может быть недостаточно большим, чтобы действительно «увидеть» логарифм - попытка выполняется при 50000 и 500000Если это занимает две секунды и двадцать секунд, то линейный рост имеет смысл.Если это займет меньше, то логарифмический имеет смысл.Если вы приблизите достаточно близко к большинству «простых» функций, результаты будут выглядеть довольно линейно.

2 голосов
/ 02 марта 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...