Я пишу что-то, что нужно начинать с списка чисел, уже по порядку, но, возможно, с пробелами и найти первый пробел, заполнить число в этом промежутке и вернуть номер, который он заполнил. Цифры - целые числа на диапазон [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 - лучший выбор для него.
Некоторые предложения:
Попробуйте другие контейнеры и сравните их. Связанный список может иметь хорошие теоретические свойства, но реальные преимущества непрерывного хранения, например, в сортированном векторе, могут быть значительными.
Поскольку ваш диапазон уже заказан, вы можете выполнить бинарный поиск, чтобы найти пробел: начните посередине, и если значение будет равным половине размера, нет пробела, поэтому вы можете ограничить поиск другой половиной. Промыть и повторить. (Это предполагает, что в диапазоне нет повторных чисел, которые, я полагаю, являются разумным ограничением, учитывая, что у вас есть понятие "пробел").
Это скорее теоретическое, отдельное предложение. Бинарный поиск в чистом связанном списке не может быть реализован очень эффективно, поэтому для использования этого подхода потребуется различная структура данных.
size() / 2
? (Конечно, вам нужен контейнер с произвольным доступом. Или создайте свою собственную древовидную структуру.)
Некоторые предложения:
Структура пробела курсора (иначе называемый "буфер пробелов") на основе std::vector
, вероятно, является самой быстрой (независимо от системы) для этого. Для реализации задайте емкость с самого начала (известную из наибольшего числа), чтобы избежать дорогостоящих динамических распределений.
Двоичный поиск можно использовать в структуре пробела курсора, а затем быстро перемещать блок для перемещения точки вставки, но измерять, если вы идете по этому маршруту: часто методы, которые являются плохими для очень большого количества элементов, таких как линейный поиск, поворот чтобы быть лучшим для небольшого количества предметов.
Сохраните позицию между вызовами, поэтому вам не нужно начинать с начала каждый раз, уменьшая общую алгоритмическую сложность для заполнения всех, от O (n 2) до O (n).
Обновление: на основе дополнительной дополнительной информации OP о том, что это случай выделения и освобождения номеров, где порядок (по-видимому) не имеет значения, самым быстрым, вероятно, является использование бесплатного списка, как это предлагается в комментарии j_random_hacker. Проще говоря, с самого начала нажимайте все доступные числа на стек, например std::stack
, свободный список. Чтобы выделить номер, просто вытащите его из стека (выбирая номер в верхней части стека), чтобы освободить номер, просто нажмите его.
std::list
- хороший выбор здесь, если списки могут быть длинными, потому что вставки O (1) против O (n) дляstd::vector
, хотя для коротких списковstd::vector
тем не менее, может быть быстрее из-за его нижний постоянный коэффициент.std::vector
потому что у меня не будет слишком много выделенных в данный момент времени. Тем не менее, я также уверен, что этот фрагмент пригодится когда-нибудь, ха-ха