Дополнительно: Как оптимизировать мой сложный алгоритм O (n²) - PullRequest
10 голосов
/ 20 сентября 2011

У меня есть данные о людях и местах:

  • Person сущность имеет
    • IList<DateRangePlaces> каждый имеет
      • IList<Place> возможных мест
    • Schedule дневная модель как т.е. 10 дней доступно 4 недоступно

В пределах определенного диапазона дат DateRangePlaces нужно подчиняться шаблону Schedule, может ли человек идти в определенное место или нет.

  • Place сущность имеет
    • IList<DateRangeTiming> каждое время открытия / закрытия в каждом диапазоне дат

Перекрывающиеся диапазоны дат работают как LIFO. Таким образом, для каждого дня, который уже был определен, предпочтение отдается новому определению времени.

проблема

Теперь мне нужно сделать что-то вроде этого (в псевдокоде):

for each Place
{
    for each Day between minimum and maximum date in IList<DateRangeTiming>
    {
        get a set of People applicable for Place and on Day
    }
}

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

.

& sum; (мест) (& sum; (дней) × & sum; (чел.) )

Это, насколько я понимаю,

O (x × y x × z)

и, вероятно, приближается к этому алгоритму сложности:

* 1 065 ** * тысячу шестьдесят-шесть О (п 3 )

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

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

Person.IList<DateRangePlaces>.IList<Place>

до

Person.IList<DateRangePlaces>.IDictionary<int, Place>

, который даст мне более быстрый результат, если человек может пойти в какое-то место в конкретную дату, потому что я проверю только наличие в словаре Place.Id вместо предложения IList.Where() LINQ, которое должно было бы сканировать весь список каждый раз.

Вопрос

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

  2. Какие типы структур памяти вы бы использовали, где и почему (списки, словари, стеки, очереди ...) для повышения производительности?

Приложение: вся проблема еще сложнее

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

Place.IList<Permission>
Person.IList<DateRangePermission>

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

В дополнение к этому, есть также

Person.IList<DateRangeTimingRestriction>

, который сообщает только определенное время, когда этот человек может пойти куда-то в течение определенного диапазона дат. И

Person.IList<DateRangePlacePriorities>

Определяет приоритеты мест для определенного диапазона дат.

И в процессе поиска подходящих людей мне также приходится рассчитывать определенный коэффициент на каждого человека в каждом месте, связанном с:

  • количество мест, которые человек может посетить в определенный день
  • фактор приоритета человека в этот день

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

Я думаю, что такая хранимая процедура была бы слишком сложной для обработки и обслуживания. Поэтому я предпочитаю сначала получить все данные (указать соответствующие структуры памяти, чтобы повысить производительность), а затем манипулировать ими в памяти.

Ответы [ 3 ]

3 голосов
/ 20 сентября 2011

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

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

3 голосов
/ 20 сентября 2011

Я предлагаю использовать реляционную базу данных и написать хранимую процедуру для получения «набора людей, применимых для места и дня».

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

Единственный способ ускорить процесс с использованием коллекций:

  1. изменить тип коллекции.Вы можете использовать KeyedCollection, IDictionary <> или даже отключенный набор записей.Отключенные наборы записей также дают вам возможность устанавливать внешние ключи для дочерних наборов записей, однако я думаю, что это будет довольно сложный шаблон для использования.

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

  3. поддерживает логические свойства, которые могут позволить вам пропускать итерации, если истина или ложь.Например, когда вы строите свои сущности, установите логическое значение «HasPlaceXPermission».если значение равно false, вы не знаете, получать информацию, связанную с местом X.

  4. поддерживать флаги - флаги могут быть очень хорошим методом оптимизации при правильном использовании.Подобно # 3, флаги можно использовать для очень быстрого определения разрешений, например, если ((person.PlacePermissions & (Place.Colorado | Place.Florida)> 0) // выполнить сканирование даты / времени в Колорадо и Флориде, иначе не't.

Трудно знать, какие типы коллекций я буду использовать, основываясь на предоставленной вами информации, мне потребуется более широкая область применения, чтобы определить это архитектурно. Например,Где хранятся данные, как они извлекаются, как они готовятся и как они представляются? Знание того, как приложение спроектировано, поможет определить точки его оптимизации.

1 голос
/ 20 сентября 2011

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

Не беспокойтесь о сложности, если у вас нет проблем с масштабированием с большим количеством людей.Обычное профилирование - это то место, с которого нужно начинать, если у вас проблемы с производительностью.O (#locations * #people) не так уж и плохо.

...