Дополнительно: как оптимизировать мой комплексный алгоритм O (n²)

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

  • 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
    }
}

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

" → " →

Это, по моему мнению,

O (x × y x × z)

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

О (п 3)Забастовкa >

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

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

Person.IList<DateRangePlaces>.IList<Place>

к

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

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

Вопрос

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

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

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

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

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

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

Кроме того, там также

Person.IList<DateRangeTimingRestriction>

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

Person.IList<DateRangePlacePriorities>

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

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

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

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

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

Ответ 1

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

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

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

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

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