2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу 1, 2  След.
 
 Задача на поисследовать
Сообщение11.07.2018, 10:39 


17/08/15
39
Добрый день! Коллеги подкинули задачу на "поисследовать"

Изначально дан массив, каждый элемент которого равен нулю. С массивом возможно проводить операции 2 типов:

1. сделать инкремент i-го элемента на 1,
2. получить индекс элемента с минимальным значением.

Предложить структуру данных, которая позволяет выполнять указанные операции над массивом и требует

1)минимум затрат по дополнительной памяти
2)минимум затрат по сложности

Из нее вытекают вопросы:

1) Если минимум по памяти, то, получается, что мы храним только сам массив и все. Тогда поиск минимума производится за $O(n)$, а инкремент за единицу. Либо можно сделать как-то оптимальнее?

2) Если минимум по сложности, то, логично, что можно положить болт на память и пользоваться ей в свое удовольствие. По умолчанию у нас массив отсортированный. При инкременте одного элемента нам надо его "пересортировать", посему - можно ли это сделать за O($\log(n)$)? Потому как за логарифм мы только найдем куда вставить увеличенный элемент, но надо же еще провести смещение блока отсортированного массива(поиск этого элемента можно не проводить, если в структуре хранить вместе со значением и номером элемента первоначального массива еще и его адрес в отсортированном массиве). Тогда, соответственно, поиск минимума - за единицу, а инкремент за логарифм(если это возможно). Вопрос - прав ли я и можно ли сделать быстрее?

Буду благодарен не за прямые ответы, а за любые наводящие вопросы, чтобы по итогу додумался сам. Спасибо

 Профиль  
                  
 
 Re: Задача на поисследовать
Сообщение11.07.2018, 11:10 
Заслуженный участник


06/07/11
5627
кран.набрать.грамота
Если мы увеличиваем один элемент на единицу за раз, то для сортировки достаточно сравнить элемент с соседом и поменять их местами. Получится такой "медленный пузырек". Изредка будет получаться смещение больше чем на одну позицию, но мне лень считать, сколько получится в итоге. Точно меньше $O(n)$ при дополнительных затратах памяти на вторую копию массива.

 Профиль  
                  
 
 Re: Задача на поисследовать
Сообщение11.07.2018, 11:32 


27/08/16
10290
mitrik в сообщении #1325824 писал(а):
2)минимум затрат по сложности

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

 Профиль  
                  
 
 Re: Задача на поисследовать
Сообщение11.07.2018, 11:43 


17/08/15
39
realeugene в сообщении #1325836 писал(а):
Вас интересует средняя сложность или в худшем? Потому что в случае прибавления единицы к случайно и независимо выбираемому элементу в сортированном массиве, эти элементы, конечно, будут переставляться иногда друг с другом, но чем дальше - тем реже.


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

 Профиль  
                  
 
 Re: Задача на поисследовать
Сообщение11.07.2018, 11:50 
Заслуженный участник


06/07/11
5627
кран.набрать.грамота
mitrik в сообщении #1325839 писал(а):
Все-таки искать минимум за линейную сложность при неограниченной памяти не очень хочется
Если вы сортируете при вставке, то поиск у вас будет за $O(1)$ - тупо первый элемент сортированного массива. Расходы будут на сортировку.

 Профиль  
                  
 
 Re: Задача на поисследовать
Сообщение11.07.2018, 11:55 


17/08/15
39
rockclimber в сообщении #1325842 писал(а):
Если вы сортируете при вставке, то поиск у вас будет за $O(1)$ - тупо первый элемент сортированного массива. Расходы будут на сортировку.


Да, пардон, сам в своих словах запутался. Почему-то кажется, что именно эту часть можно минимизировать, только не придумал как. Смещение массива влево, в худшем случае будет иметь линейную сложность

 Профиль  
                  
 
 Re: Задача на поисследовать
Сообщение11.07.2018, 12:14 


10/04/12
705
А просто хранить в виде кучи пары значение/индекс?

Двоичная куча
Биномиальная куча
Фибоначчиева куча

Фибоначчиева куча, похоже, самое то:
Цитата:
Кроме стандартных операций INSERT, MIN, DECREASE-KEY, фибоначчиева куча позволяет за время $O(1)$ выполнять операцию UNION слияния двух куч.

 Профиль  
                  
 
 Re: Задача на поисследовать
Сообщение11.07.2018, 12:20 


17/08/15
39
mustitz в сообщении #1325848 писал(а):
А просто хранить в виде кучи пары значение/индекс?


А как в таком случае производить сам инкремент? А точнее поиск нужного индекса? Куча же будет построена относительно значений

 Профиль  
                  
 
 Re: Задача на поисследовать
Сообщение11.07.2018, 12:27 
Аватара пользователя


11/12/16
13881
уездный город Н
1. Храним индекс минимального элемента. Больше ничего. (upd: соответственно, возвращаем минимальный элемент всегда за O(1))
2. Массив не сортируем.
3. Инкрементируем за O(1).
4. Если инкрементировали не минимальный элемент, то и прекрасно.
5. Если инкрементировали минимальный элемент, то ищем новый минимальный и запоминаем его индекс. Например, один проход пузырька за O(n)

Так как пункт 5 реализуется в одном случае из n, то в среднем он даст добавку к сложности O(1).

 Профиль  
                  
 
 Re: Задача на поисследовать
Сообщение11.07.2018, 12:38 


10/04/12
705
mitrik в сообщении #1325851 писал(а):
mustitz в сообщении #1325848 писал(а):
А просто хранить в виде кучи пары значение/индекс?


А как в таком случае производить сам инкремент? А точнее поиск нужного индекса? Куча же будет построена относительно значений


Мы храним оригинальный индекс элемента $i$, он неизменен. И мы храним текущее значение $v$, которое можно инкрементировать. Соответственно, чтобы получить индекс наименьшего элемента мы просто берём верхушку кучи и возвращаем оттуда индекс. Инкремент узла $(i, v)$ это по сути изменение значения на $(i, v+1)$. Вопрос только в том, что это увеличение значения ключа (а не уменьшение), и Фиббоначиева куча скорее всего не будет работать :( Но по крайней мере направление движения ясно. Но даже простая замена изменения на две операции удалить/добавить в случае если если инкремет меняет расположение узлов (простая проверка) даст нам $O(\log N)$.

 Профиль  
                  
 
 Re: Задача на поисследовать
Сообщение11.07.2018, 12:59 


27/08/16
10290
mitrik в сообщении #1325839 писал(а):
Обе оценки важны, но мне кажется, что предпочтительна будет в худшем. Все-таки искать минимум за линейную сложность при неограниченной памяти не очень хочется
Пузырёк в худшем даёт $O(N)$ конечно. Если только параллельно с сортированным списком не хранить список интервалов в этом списке с одинаковыми значениями элементов. Тогда вспылытие элемента при инкременте его значения можно выполнить за $O(1)$.

 Профиль  
                  
 
 Re: Задача на поисследовать
Сообщение11.07.2018, 13:02 
Заслуженный участник
Аватара пользователя


16/07/14
9166
Цюрих
EUgeneUS в сообщении #1325853 писал(а):
Так как пункт 5 реализуется в одном случае из n, то в среднем он даст добавку к сложности O(1).
Может и каждый раз реализовываться.
rockclimber в сообщении #1325832 писал(а):
Изредка будет получаться смещение больше чем на одну позицию, но мне лень считать, сколько получится в итоге. Точно меньше $O(n)$ при дополнительных затратах памяти на вторую копию массива.
Может почти всегда получаться больше, если всегда увеличивать самый левый элемент. Таким образом из всех нулей получим все единицы за $(n - 1) + (n - 2) + \ldots + 1$ сдвигов и $n$ инкрементов.

Но за $O(1)$ всё равно можно - нужно хранить сортированный связный список (значение, связный список элементов с этим значением) (ну и для каждого индекса - где в каком списке он лежит). При увеличении элемента переносим его в следующий список верхнего уровня (при необходимости создаем), ставшие пустыми списки убираем. Каждый инкремент и поиск минимума делается строго за константу.

 Профиль  
                  
 
 Re: Задача на поисследовать
Сообщение11.07.2018, 13:17 
Аватара пользователя


11/12/16
13881
уездный город Н
mihaild в сообщении #1325867 писал(а):
Может и каждый раз реализовываться.

Может, поэтому O(1) только в среднем, а в худшем O(n), конечно.
И что-то мне подсказывает, что без создания новых структур данных ("индексов") лучше не сделать.

 Профиль  
                  
 
 Re: Задача на поисследовать
Сообщение11.07.2018, 13:23 


27/08/16
10290
Можно ещё выполнить эти операции за амортизированное время O(1) и всего с двумя дополнительными ячейками памяти. Например, мы кроме самого массива храним индекс последнего найденного минимального элемента и его значение. Инициализируя индексом последнего элемента в массиве и значением -1 (впрочем, два нуля тоже работают). При запросе минимума выдаём текущий последний индекс, если его значение совпадает со старым, или идём в конец массива и далее по кругу, ища первое совпадение, и при возврате в начало массива увеличивая искомое значение на 1.

PS Ну как, "поисследовали"?

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

 Профиль  
                  
 
 Re: Задача на поисследовать
Сообщение11.07.2018, 14:00 


17/08/15
39
EUgeneUS в сообщении #1325853 писал(а):
1. Храним индекс минимального элемента. Больше ничего. (upd: соответственно, возвращаем минимальный элемент всегда за O(1))
2. Массив не сортируем.
3. Инкрементируем за O(1).
4. Если инкрементировали не минимальный элемент, то и прекрасно.
5. Если инкрементировали минимальный элемент, то ищем новый минимальный и запоминаем его индекс. Например, один проход пузырька за O(n)

Так как пункт 5 реализуется в одном случае из n, то в среднем он даст добавку к сложности O(1).


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

mustitz в сообщении #1325857 писал(а):
Мы храним оригинальный индекс элемента $i$, он неизменен. И мы храним текущее значение $v$, которое можно инкрементировать. Соответственно, чтобы получить индекс наименьшего элемента мы просто берём верхушку кучи и возвращаем оттуда индекс. Инкремент узла $(i, v)$ это по сути изменение значения на $(i, v+1)$. Вопрос только в том, что это увеличение значения ключа (а не уменьшение), и Фиббоначиева куча скорее всего не будет работать :( Но по крайней мере направление движения ясно. Но даже простая замена изменения на две операции удалить/добавить в случае если если инкремет меняет расположение узлов (простая проверка) даст нам $O(\log N)$.


Насчет кучи подумаю как это можно реализовать, идея точно жизнеспособная, хоть и геморройная немного)))

mihaild в сообщении #1325867 писал(а):
Но за $O(1)$ всё равно можно - нужно хранить сортированный связный список (значение, связный список элементов с этим значением) (ну и для каждого индекса - где в каком списке он лежит). При увеличении элемента переносим его в следующий список верхнего уровня (при необходимости создаем), ставшие пустыми списки убираем. Каждый инкремент и поиск минимума делается строго за константу.


Так удаление элемента по значению из списка вроде линейная операция или я что-то совсем попутал?

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 18 ]  На страницу 1, 2  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group