Я запустил 2 кода в Python, а затем измерил время, необходимое для завершения. Коды довольно простые, просто рекурсивные максимумы. Вот оно: 1.

def max22(L, left, right):
  if(left>=right):
    return L[int(left)]
  k = max22(L,left,(left+right-1)//2)
  p = max22(L, (right+left+1)//2,right)
  return max(k,p)


def max_list22(L):
  return max22(L,0,len(L)-1)

def max2(L):
  if len(L)==1:
    return L[0]
  l = max2(L[:len(L)//2])
  r = max2(L[len(L)//2:])
  return max(l,r)

Первый должен работать (imo) в O (logn), а второй в O (n * logn). Однако я измерил время работы для n = 1000, n = 2000 и n = 4000, и почему-то рост для обоих алгоритмов кажется линейным! Как это возможно? Я неправильно понял сложность или все в порядке? Благодарю.

3
Bar 16 Дек 2015 в 00:36

3 ответа

Лучший ответ

Тот факт, что функция разделяет пространство поиска на 2, а затем рекурсивно просматривает каждую половину, не означает, что она имеет логарифмический (n) фактор сложности.

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

2
MAK 15 Дек 2015 в 21:57

Первый алгоритм не O(log n), потому что он проверяет значение каждого элемента. Можно показать, что это O(n)

Что касается второго, возможно, вы просто не могли заметить разницу между n и nlogn в таких небольших масштабах.

3
RiaD 15 Дек 2015 в 21:58

Ваш первый алгоритм - O (n) на обычной машине, поэтому неудивительно, что тестирование показало это. Ваш второй алгоритм O (n * log-in), но он был бы O (n), если бы вы использовали правильные массивы вместо списков. Поскольку операции со встроенным списком Python довольно быстрые, возможно, вы еще не достигли логарифмического замедления; попробуйте с такими значениями, как n=4000000 и посмотрите, что вы получите.

Обратите внимание, что если бы вы могли выполнять оба рекурсивных вызова параллельно (с нарезкой O (1)), оба алгоритма могли бы выполняться за время O (log n). Конечно, для этого вам понадобится O (n) процессоров, но если бы вы разрабатывали микросхему вместо написания программы, то такое масштабирование было бы простым ...

0
comingstorm 16 Дек 2015 в 07:12