Форум русскоязычного сообщества Ubuntu


Считаете, что Ubuntu недостаточно дружелюбна к новичкам?
Помогите создать новое Руководство для новичков!

Автор Тема: поиск максимального подмассива  (Прочитано 3774 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн DenisVASI

  • Автор темы
  • Участник
  • *
  • Сообщений: 116
    • Просмотр профиля
Re: поиск максимального подмассива
« Ответ #15 : 31 Июля 2015, 21:00:00 »
Извиняюсь, что-то не увидел :) сейчас гляну

Оффлайн SkinnyJack

  • Любитель
  • *
  • Сообщений: 53
    • Просмотр профиля
Re: поиск максимального подмассива
« Ответ #16 : 31 Июля 2015, 21:20:36 »
я извиняюсь за излишнюю настойчивость, но на мой изначальный вопрос так ответа и не дали, где в моём коде ошибка?
Да в добрый путь. Ошибка в функции find_max_subarray в ветке else.
циклится вот тут
Код: (python) [Выделить]
left_low, left_high, left_sum = find_max_subarray(a, low, mid)
конкретно при значениях low=0, high=1.
Долго ли коротко, расковырял и пофиксил строка 24:
Код: (python) [Выделить]

...
    if high == low+1:
...
Но опять ошибка. Теперь строка 15:
Код: (python) [Выделить]
...
    for j in range(mid+1, high, 1):
...
и результат:
(7, 10, 43)
а значит и знания которые я тут получу будут распространяться на все мои будущие программы
Браво! Теперь вы знаете что нужно внимательно следить за индексами, но отлаживать свой код так и не научились.
« Последнее редактирование: 31 Июля 2015, 21:22:54 от SkinnyJack »

Оффлайн DenisVASI

  • Автор темы
  • Участник
  • *
  • Сообщений: 116
    • Просмотр профиля
Re: поиск максимального подмассива
« Ответ #17 : 31 Июля 2015, 21:24:11 »
Извиняюсь, с телефона читал, спойлер проглядел, а относительно ваших тестов, где-то в книге был интересный пример, когда сортировка вставками работала быстрее слияния с относительно небольшими массивами, но после перехода к более большим величинам становилась на порядок медленнее.
Например, как известно время работы сортировки вставками n^2, слияние n lg n,
если взять массив на 100000000 элементов, а компьютер будет выполнять 300.000.000 команд в секунду то получим:
((10^7)^2)/300.000.000 = 333333, (3) секунд
(10 ^ 7 lg 10 ^ 7)/300.000.000 = 0, 23 секунд

я думаю что похожий принцип действует и на эти алгоритмы.

p.s : честно говоря такое ощущение что глупость написал, уж слишком результаты не правдоподобны, я специально не стал брать константу перед формулой (типа cn^2) так как соотношение бы не изменилось  ;)


Пользователь решил продолжить мысль 31 Июля 2015, 21:27:44:
SkinnyJack, научусь, спасибо)
« Последнее редактирование: 31 Июля 2015, 21:27:44 от DenisVASI »

Оффлайн Sly_tom_cat

  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: поиск максимального подмассива
« Ответ #18 : 31 Июля 2015, 22:46:12 »
DenisVASI, да нет - все правильно вы написали. Только не надо пытаться обсчитать вычислительную сложность алгоритма. Это понятие для того и формализуется до простых функций, что бы давать обобщенное представление о времени работы алгоритма.

Допустим всем и так понятно, что алгоритм со сложностью О(n^3) будет медленнее чем O(n^2) именно при больших объемах вычисления. А на малых объемах вычислений, даже O(n!) будет не сильно отличаться от первых двух.

При этом грубо оценку дать можно просто по структуре кода. Если у вас один цикл - то это линейная сложность.
Если один вложен в другой - это уже квадратичная.
« Последнее редактирование: 31 Июля 2015, 22:48:24 от Sly_tom_cat »
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Оффлайн Sly_tom_cat

  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: поиск максимального подмассива
« Ответ #19 : 04 Августа 2015, 08:29:09 »
Кстати, по поводу рекурсии, с подачи этой темы нашел тут интересную книжку "Python Algorithms Mastering Basic Algorithms in the Python Language" Magnus Lie Hetland (на английском) там довольно любопытный пример есть.
(Нажмите, чтобы показать/скрыть)
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Оффлайн DenisVASI

  • Автор темы
  • Участник
  • *
  • Сообщений: 116
    • Просмотр профиля
Re: поиск максимального подмассива
« Ответ #20 : 04 Августа 2015, 22:00:52 »
Всем снова здравствуйте, вынужден вернуться к этой теме, т.к изменения предложенные SkinnyJack не помогли программе запуститься. Я пробовал ее изменять, но не получается.
Вот код целиком:
Код: (python) [Выделить]
__author__ = 'Denis'


def crossing_sub_arr(arr, low, mid, high):
    left_sum = -1e308
    buf = 0
    max_left = 0
    for i in range(mid, low, -1):
        buf += arr[i]
        if buf > left_sum:
            left_sum = buf
            max_left = i
    right_sum = -1e308
    buf = 0
    max_right = 0
    for j in range(mid + 1, high, 1):
        buf += arr[i]
        if buf > right_sum:
            right_sum = buf
            max_right = j
    return max_left, max_right, left_sum + right_sum


def find_max_sub_arr(arr, low, high):
    if high == low + 1:
        return low, high, arr[low]
    else:
        mid = int((low + high) / 2)
        left_l, left_h, left_s = find_max_sub_arr(arr, low, mid)
        right_l, right_h, right_s = find_max_sub_arr(arr, mid + 1, high)
        cross_l, cross_h, cross_s = crossing_sub_arr(arr, low, mid, high)
    if left_s >= right_s and left_s >= cross_s:
        return left_l, left_h, left_s
    elif right_s >= left_s and right_s >= cross_s:
        return right_l, right_h, right_s
    else:
        return cross_l, cross_h, cross_s

arr = [13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7]

low, r, s = find_max_sub_arr(arr, 0, len(arr))

print(low, r, s)
Если использовать его то на 6 итерации когда и low, и high будут равны 2 if сравнит 2 с 3 и рекурсия зациклится.
Если убрать +1 к low во время сравнения то будет выход за пределы массива в отрезке кода:
Код: (python) [Выделить]
return low, high, arr[low]
и что делать дальше я не понимаю, всем заранее спасибо.

Пользователь решил продолжить мысль 04 Августа 2015, 22:07:29:
если что, у меня python 3.4.3
« Последнее редактирование: 04 Августа 2015, 22:07:29 от DenisVASI »

Оффлайн SkinnyJack

  • Любитель
  • *
  • Сообщений: 53
    • Просмотр профиля
Re: поиск максимального подмассива
« Ответ #21 : 04 Августа 2015, 22:48:27 »
Код: (python) [Выделить]
m = [13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7]
 
def find_max_crossing_subarray(a, low, mid, high):
    left_sum = -1e308
    s = 0
    for i in range(mid, low, -1):
        s += a[i]
        if s > left_sum:
            left_sum = s
            max_left = i
    right_sum = -1e308
    max_right = right_sum
    s = 0
    for j in range(mid+1, high, 1):
        s += a[j]
        if s > right_sum:
            right_sum = s
            max_right = j
    return max_left, max_right, left_sum + right_sum
 
 
def find_max_subarray(a, low, high):
    if high == low+1:
        return low, high, a[low]
    else:
        mid = (low + high) / 2
        left_low, left_high, left_sum = find_max_subarray(a, low, mid)
        right_low, right_high, right_sum = find_max_subarray(a, mid, high)
        cross_low, cross_high, cross_sum = find_max_crossing_subarray(a, low, mid+1, high)
        if left_sum >= right_sum and left_sum >= cross_sum:
            return left_low, left_high, left_sum
        if right_sum >= left_sum and right_sum >= cross_sum:
            return right_low, right_high, right_sum
        else:
            return cross_low, cross_high, cross_sum
 
min, max, sum = find_max_subarray(m, 0, 15)
print(min, max, sum)

УМВР ЧЯДНТ?

Оффлайн DenisVASI

  • Автор темы
  • Участник
  • *
  • Сообщений: 116
    • Просмотр профиля
Re: поиск максимального подмассива
« Ответ #22 : 05 Августа 2015, 12:19:22 »
Всё равно что-то не так.
Вот скрин кода прямо из ide: http://rghost.ru/7WzQYjDN5/image.png
И вот ответ который ide мне даёт: http://rghost.ru/899C7QLCg/image.png
Я не знаю что вы делаете не так, но оно не работает.


Оффлайн Sly_tom_cat

  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: поиск максимального подмассива
« Ответ #23 : 05 Августа 2015, 13:25:14 »
DenisVASI, я не очень понимаю зачем вам отлаживать такой навороченный с рекурсиями код когда есть простое с линейным временм исполнения решение:
Код: (python) [Выделить]
def max_sum_part(a):
  max_sum = 0
  left = 0
  right = 0
  s = 0
  minus_pos = -1
 
  for i in range(len(a)):
    s += a[i]
    if s > max_sum:
      max_sum = s
      left = minus_pos + 1
      right = i
    if s < 0:
      s = 0
      minus_pos = i
  return(max_sum, left, right)
Если вопрос чисто академический - то проще рекурсию на других примерах поизучать - тут задача слишком линейная.
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Оффлайн Sly_tom_cat

  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: поиск максимального подмассива
« Ответ #24 : 05 Августа 2015, 14:39:15 »
Кстати еще ошибку у вас нашел:

вы когда делите диапазон от low до high на две части то вам нужно учитывать что low не всегда ноль, а потому нужно задавать начальное смещение. Индекс середины диапазона ну никак не может быть равен (high + low)/2 - это просто бред акой-то, а не середина. Подумайте немного сами
(Нажмите, чтобы показать/скрыть)

Кроме того деление массива на две части и поиск в дух частях отдельно и массива с пересечениями - выглядит просто излишним наворотом.

Вы совершенно не правильно применили в этом решении принцип "разделяй и властвуй", точнее сказать тут не нужно применять этот принцип т.к. достаточно проследить последовательность расчета и понять что тут можно все решить линейным проходом по массиву от начала до конца. И решения типа того что в прошлом моем посте работают с просто изумительной скоростью - обсчет массива из 1000000 элементов у меня делается за 0.147897-0.176961 сек.
« Последнее редактирование: 05 Августа 2015, 15:36:23 от Sly_tom_cat »
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Оффлайн DenisVASI

  • Автор темы
  • Участник
  • *
  • Сообщений: 116
    • Просмотр профиля
Re: поиск максимального подмассива
« Ответ #25 : 05 Августа 2015, 16:58:16 »
это хочу заметить не я его придумал тут применять, вот фото из книги, которую мне рекомендовали пара программистов.
Здесь это реализовано именно так.
функция 1: http://rghost.ru/6TF68kf6p/image.png
функция 2: http://rghost.ru/7bPfwXsS2/image.png
однако, как вы можете видеть, что-то оно не работает.

Оффлайн Sly_tom_cat

  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: поиск максимального подмассива
« Ответ #26 : 05 Августа 2015, 17:28:49 »
А что в книгах не бывает опечаток? Да их полно.

Деление массива на две части дает еще одну проблему - поиска суммы пересекающей границу разделения - которая по сути сводит смысл деления к 0, потому что на пересечении искать - то же самое что искать от начала и до конца НЕ ДЕЛЯ массив на две части.

Собственно рекурсию тут вообще не понятно к чему прикручивать - линейный алгоритм до мозга и костей.
« Последнее редактирование: 05 Августа 2015, 17:43:07 от Sly_tom_cat »
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

Оффлайн Sly_tom_cat

  • Don't worry, be happy!
  • Заслуженный пользователь
  • Старожил
  • *
  • Сообщений: 12130
  • Xubuntu 22.04
    • Просмотр профиля
    • Github
Re: поиск максимального подмассива
« Ответ #27 : 05 Августа 2015, 17:50:02 »
Вот самый оптимальный по времени исполнения код, полученный после множества эксперементов:

Код: (python) [Выделить]
def max_subarray(a):
  pos = left = right = 0
  max_s = s = a[0]
  for i in range(1, len(a)):
    if s < 0:
      s, pos = a[i], i
    else:
      s += a[i]
    if s > max_s:
      max_s, left, right = s, pos, i
  return max_s, left, right


Удивительно что даже замена
Код: (python) [Выделить]
    if s > max_s:на
Код: (python) [Выделить]
    if max_s < s:дает ухудшение результата.

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

Так же ухудшает результат если цикл организовывать не по индексу массива, а по самим элементам массива (индекс при этом приходится отслеживать дополнительно).

Но в любом случае - это алгоритм сложностью O(n) что уже очень не плохо.
« Последнее редактирование: 05 Августа 2015, 17:57:05 от Sly_tom_cat »
Индикатор для Yandex-Disk: https://forum.ubuntu.ru/index.php?topic=241992
UEFI-Boot - грузимся без загрузчика: https://help.ubuntu.ru/wiki/uefiboot

 

Страница сгенерирована за 0.036 секунд. Запросов: 25.