Анализ временной сложности кода

Следующий код должен отображать все ошибки:

<?php

// ----------------------------------------------------------------------------------------------------
// - Display Errors
// ----------------------------------------------------------------------------------------------------
ini_set('display_errors', 'On');
ini_set('html_errors', 0);

// ----------------------------------------------------------------------------------------------------
// - Error Reporting
// ----------------------------------------------------------------------------------------------------
error_reporting(-1);

// ----------------------------------------------------------------------------------------------------
// - Shutdown Handler
// ----------------------------------------------------------------------------------------------------
function ShutdownHandler()
{
    if(@is_array($error = @error_get_last()))
    {
        return(@call_user_func_array('ErrorHandler', $error));
    };

    return(TRUE);
};

register_shutdown_function('ShutdownHandler');

// ----------------------------------------------------------------------------------------------------
// - Error Handler
// ----------------------------------------------------------------------------------------------------
function ErrorHandler($type, $message, $file, $line)
{
    $_ERRORS = Array(
        0x0001 => 'E_ERROR',
        0x0002 => 'E_WARNING',
        0x0004 => 'E_PARSE',
        0x0008 => 'E_NOTICE',
        0x0010 => 'E_CORE_ERROR',
        0x0020 => 'E_CORE_WARNING',
        0x0040 => 'E_COMPILE_ERROR',
        0x0080 => 'E_COMPILE_WARNING',
        0x0100 => 'E_USER_ERROR',
        0x0200 => 'E_USER_WARNING',
        0x0400 => 'E_USER_NOTICE',
        0x0800 => 'E_STRICT',
        0x1000 => 'E_RECOVERABLE_ERROR',
        0x2000 => 'E_DEPRECATED',
        0x4000 => 'E_USER_DEPRECATED'
    );

    if(!@is_string($name = @array_search($type, @array_flip($_ERRORS))))
    {
        $name = 'E_UNKNOWN';
    };

    return(print(@sprintf("%s Error in file \xBB%s\xAB at line %d: %s\n", $name, @basename($file), $line, $message)));
};

$old_error_handler = set_error_handler("ErrorHandler");

// other php code

?>

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

12
задан Bill the Lizard 16 September 2012 в 22:11
поделиться

7 ответов

Пусть

L3 = логарифм по основанию 3 L2 = войти в базу 2

Тогда правильный ответ будет O (L3 (L2 (n)) , а НЕ O (L2 (L2 (n)).

] Начните с x = x * 2 . X будет увеличиваться экспоненциально, пока не достигнет n, что сделает временную сложность O (L2 (n))

Теперь рассмотрим x = x * x . X увеличивается быстрее, чем указано выше. На каждой итерации значение x перескакивает к квадрату его предыдущего значения. Выполнив простую математику, мы получим следующее:

Для x = 2 n = 4, сделано итераций = 1 n = 16, сделано итераций = 2 n = 256, сделано итераций = 3 n = 65536, итераций = 4

Таким образом, временная сложность составляет O (L2 (L2 (n)) . Вы можете проверить это, поместив значения выше значений для n.

Теперь придет к вашей проблеме: x = x * x * x . Оно будет увеличиваться даже быстрее, чем x = x * x. Вот таблица:

Для x = 2 n = 8, сделано итераций = 1 n = 512, сделано итераций = 2 n = (512 * 512 * 512), количество выполненных итераций = 3 и так далее

Если вы посмотрите внимательно, то окажется, что это O (L3 (L2 (n)) . L2 ( n) даст вам степень двойки, но, поскольку вы берете куб x на каждой итерации, вам нужно будет записать его в базу 3, чтобы узнать правильное количество сделанных итераций.

Так что я думаю правильный ответ: O (log-to-base-3 (log-to-base-2 (n))

Обобщая это, если x = x * x * x * x * .. (k раз) , тогда сложность времени равна O (log-to-base-k (log-to-base-2 (n)

2
ответ дан 2 December 2019 в 19:31
поделиться

воспринимайте это как рекурсивную функцию:

f(i) = f(i-1)^3

если вы расширяете ее:

f(i) = ((f(i-k)^3)^3)[...k times] = f(i-k)^(3^k) = f(0)^(3^i)

функция растет по мере увеличения мощности ... поэтому время (итераций) для достижения определенное число (то есть вычисление обратной функции) является логарифмом логарифма.

Как и в вашем примере f (0) = 2 , мы хотим знать, когда f ( i)> = n , являющееся n входным параметром (и i количество итераций):

f(i) = 2^(3^i) >= n
           3^i >= log_2(n)
             i >= log_3(log_2(n))

Таким образом, чтобы достичь значения n , он принимает log_3 (log_2 (n)) итераций (округление в большую сторону при работе с целыми числами, чтобы превзойти его).

если бы функция была:

f(i) = 2*f(i-1) //e.g. x=2*x

, то шаблон был бы:

f(i) = 2*2*[...k times]*f(i-k) = f(i-k)*(2^k) = f(0)*(2^i)

И в этом случае функция, обратная функции, будет логарифмом по основанию 2.

Мои вычисления не очень строгие, но я надеюсь, что вы »Я уловлю идею.

9
ответ дан 2 December 2019 в 19:31
поделиться

Если бы код внутри цикла while был

x = 2*x;

, x достиг бы n за O (log (n)) итераций. Поскольку вы занимаетесь кубом x, а не просто умножаете его на константу, вы достигнете n быстрее.

1
ответ дан 2 December 2019 в 19:31
поделиться

Учитывая

log ( A * x )     == log ( A ) + log ( x )
log ( x * x * x ) == 3 * log ( x )

Итак

log ( log ( x * x * x ) ) == log ( 3 * log ( x ) )
                          == log ( 3 ) + log ( log ( x ) )

Насколько быстрее или медленнее (измеряется количеством итераций цикла) будет ли эта функция отличаться от вашей?

int log_foo ( int n ) 
{
    double          log_x = log ( 2 );
    const double    log_n = log ( n );

    while ( log_x < log_n )
    {
        log_x = 3 * log_x;
    }

    return exp ( log_x );
}

И насколько эта функция будет быстрее или медленнее, чем ваша функция?

int log_log_foo ( int n ) 
{
    double          log_log_x = log ( log ( 2 ) );
    const double    log_log_n = log ( log ( n ) );
    const double    log_3     = log ( 3 );

    while ( log_log_x < log_log_n )
    {
        log_log_x += log_3;
    }

    return exp ( exp ( log_log_x ) );
}

Но эта функция увеличивает log_log_x только на константу, поэтому ее легко вычислить сколько итераций он делает.

1
ответ дан 2 December 2019 в 19:31
поделиться

Подумайте о том, как x изменяется с числом итераций в цикле. Каждый раз вы собираете его в куб. Итак, после i итераций значение будет 2 раза в кубе, снова в кубе ... и так далее, i раз. Давайте использовать x (i) для обозначения этого выражения. Скажем, x (0) = 2, x (1) = 2 3 и т. Д. (Я использую b для обозначения возведения в b-ю степень).

Мы закончили, когда x (я)> = п. Сколько времени это занимает? Давайте решим для i.

First, we take a log on both sides: ln(x(i))>=ln(n)

ln(x(i)) = ln(x(i-1))*3 = ln(x(i-2))*(3**2) = ... = ln(x(0))*(3**i)

(the above uses [this property][1]: ln(x**b)==ln(x)*b)

so, 3**i * 2 >=ln(n). Let's take another logarithm:

ln(3**i * 2) = ln(2) + ln(3)*i 

so ln(2) + ln(3)* i >= ln(ln(n))

Now we can solve for i: i >= ( ln(ln(n))-ln(2) ) / ln(3)

Мы можем игнорировать постоянные множители, и нам остается сделать вывод, что мы предпримем log (log (n)) шагов. В этом сложность вашего алгоритма.

Надеюсь, что подобная разбивка всех шагов поможет.

4
ответ дан 2 December 2019 в 19:31
поделиться

Пусть i будет числом шагов итерации, а x (i) значение x после i шагов. У нас есть

x(0) = 2
x(i) = x(i-1)³

Общее количество шагов является наибольшим i , так что x (i) .

У нас есть

log x(i) = log x(i-1)³
         = 3·log x(i-1)
         = 3·log x(i-2)³
         = 3²·log x(i-2)
         = 3^i·log x(0)
         = 3^i·log 2

⇒  log log x(i) = log (3^i·log 2)
                 = log 3^i + log log 2
                 = i·log 3 + log log 2

Логарифм строго возрастает, поэтому

x(i) < n ⇔        log log x(i) < log log n
         ⇔ i·log 3 + log log 2 < log log n
         ⇔                   i < (log log n - log log 2) / log 3 ∈ O(log log n)
1
ответ дан 2 December 2019 в 19:31
поделиться

Почему бы не добавить переменную-счетчик для подсчета количества итераций цикла. Распечатайте его непосредственно перед возвратом функции.

Затем вызовите функцию для диапазона значений, например, от 3 до 1 000 000 для начала. Затем постройте свой результат, используя что-то вроде GNUPlot .

Затем проверьте, соответствует ли график известной кривой.

0
ответ дан 2 December 2019 в 19:31
поделиться
Другие вопросы по тегам:

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