Эффективно заполнить первый пробел в упорядоченном списке номеров

0

Я пишу что-то, что нужно начинать с списка чисел, уже по порядку, но, возможно, с пробелами и найти первый пробел, заполнить число в этом промежутке и вернуть номер, который он заполнил. Цифры - целые числа на диапазон [0, inf). У меня это есть, и он отлично работает:

list<int> TestList = {0, 1, 5, 6, 7};

int NewElement;
if(TestList.size() == 0)
{
    NewElement = 0;
    TestList.push_back(NewElement);
}
else
{
    bool Selected = false;
    int Previous = 0;
    for(auto Current = TestList.begin(); Current != TestList.end(); Current++)
    {
        if(*Current > Previous + 1)
        {
            NewElement = Previous + 1;
            TestList.insert(Current, NewElement);
            Selected = true;
            break;
        }
        Previous = *Current;
    }
    if(!Selected)
    {
        NewElement = Previous + 1;
        TestList.insert(TestList.end(), NewElement);
    }
}

Но я беспокоюсь об эффективности, так как я использую эквивалентный фрагмент кода для выделения единых мест привязки блоков в OpenGL за оболочкой класса, которую я написал (но это не совсем актуально для вопроса :)). Любые предложения по повышению эффективности? Я даже не уверен, что std :: list - лучший выбор для него.

  • 1
    Это абсолютно нормально. std::list - хороший выбор здесь, если списки могут быть длинными, потому что вставки O (1) против O (n) для std::vector , хотя для коротких списков std::vector тем не менее, может быть быстрее из-за его нижний постоянный коэффициент.
  • 0
    Круто, я могу пойти с std::vector потому что у меня не будет слишком много выделенных в данный момент времени. Тем не менее, я также уверен, что этот фрагмент пригодится когда-нибудь, ха-ха
Теги:
list
algorithm
stl

2 ответа

3
Лучший ответ

Некоторые предложения:

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

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

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

  • 0
    Каков наилучший способ быстрого доступа к среднему элементу для двоичного поиска?
  • 1
    @mebob: Произвольный доступ в size() / 2 ? (Конечно, вам нужен контейнер с произвольным доступом. Или создайте свою собственную древовидную структуру.)
Показать ещё 3 комментария
1

Некоторые предложения:

  • Структура пробела курсора (иначе называемый "буфер пробелов") на основе std::vector, вероятно, является самой быстрой (независимо от системы) для этого. Для реализации задайте емкость с самого начала (известную из наибольшего числа), чтобы избежать дорогостоящих динамических распределений.

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

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


Обновление: на основе дополнительной дополнительной информации OP о том, что это случай выделения и освобождения номеров, где порядок (по-видимому) не имеет значения, самым быстрым, вероятно, является использование бесплатного списка, как это предлагается в комментарии j_random_hacker. Проще говоря, с самого начала нажимайте все доступные числа на стек, например std::stack, свободный список. Чтобы выделить номер, просто вытащите его из стека (выбирая номер в верхней части стека), чтобы освободить номер, просто нажмите его.

  • 0
    Я не пытаюсь заполнить их все, я на самом деле просто использую его для выделения чисел из списка (что-то для буферов OpenGL). В списке содержатся все используемые номера, и при разных вызовах могут быть разные пропуски. Тем не менее, я думаю, что я могу использовать что-то, основанное на std :: vector, так как у меня не будет большого числа чисел там в данный момент времени.
  • 0
    о, распределение. тогда, может быть, есть также - освобождение? резко меняет картину.
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню