Более простой подход с использованием петель.
IEnumerable> GetList(IEnumerable source)
{
while(source.Any())
{
var returnValue = source.TakeWhile(x=>!x.Equals("and")).ToList();
yield return returnValue;
source = source.Skip(returnValue.Count()+1);
}
}
Теперь вы можете сделать,
var words = new[] { "visit", "houston", "and", "san", "antonio", "and", "austin", "and", "corpus", "christi" };
var result = GetList(words);
Выход
Возможно создать диспетчер "кучи", который очень эффективен для объектов, которые являются всеми одинаковыми размер. Вы могли создать одну из этой "кучи" для каждого размера объекта, в котором Вы нуждаетесь, или если Вы не возражаете использовать немного пространства, создаете один для 16-байтовых объектов, один для 32, и один для 64. Максимум наверху составил бы 31 байт для 33-байтового выделения (который пойдет на 64 blocksize "кучи").
Чтобы подробно остановиться, что Greg Hewgill говорит, один способ сделать, ультраэффективная "куча" фиксированного размера:
Очевидно, шаг 3 также должен проверить, делает ли пустой список, и раз так набор работы, получая новый большой буфер (или сбой).
Еще более эффективный, как Greg говорят D и hazzen, должен выделить путем постепенного увеличения или постепенного уменьшения указателя (1 загрузка, 1 хранилище), и не предложить способ освободить единственный узел вообще.
Править: В обоих случаях, свободный может иметь дело со сложностью "что-либо большее, я передаю обычный диспетчер "кучи"" полезным тем, что Вы возвращаете размер в вызове к свободному. Иначе Вы посмотрели бы на любого флаг (наверху, вероятно, 4 байта за узел) или иначе поиск в некоторой записи буфера (буферов), который Вы использовали.
Ответ может зависеть от пожизненных шаблонов для этих объектов. Если объекты все инстанцируют, в то время как Вы продолжаете двигаться, и затем все удаленные одним махом, может иметь смысл создавать очень простой диспетчер "кучи", который выделяет память путем простого постепенного увеличения указателя. Затем когда Вы сделаны, сдуваете всю "кучу".
Raymond Chen сделал интересное сообщение, которое может помочь вдохновить Вас.:)
Если набор памяти будет выделен, будет использовать и будет освобождать перед хождением дальше к следующему раунду выделения, то я предложу использовать самое простое возможное средство выделения:
typedef struct _allocator {
void* buffer;
int start;
int max;
} allocator;
void init_allocator(size_t size, allocator* alloc) {
alloc->buffer = malloc(size);
alloc->start = 0;
alloc->max = size;
}
void* allocator_malloc(allocator* alloc, size_t amount) {
if (alloc->max - alloc->start < 0) return NULL;
void* mem = alloc->buffer + alloc->start;
alloc->start += bytes;
return mem;
}
void allocator_free(allocator* alloc) {
alloc->start = 0;
}
Мне нравится ответ onebyones.
Вы могли бы также рассмотреть систему приятеля для своих наборов "кучи" фиксированного размера.
Я использую в основном O (1) Small Block Memory Manager (SBMM). В основном это работает следующим образом:
1) Он выделяет большие суперблоки из ОС и отслеживает начальные и конечные адреса как диапазон. Размер суперблока можно регулировать, но 1 МБ - это неплохой размер.
2) Суперблоки разбиты на блоки (также регулируемые по размеру ... 4K-64K хорошо в зависимости от вашего приложения). Каждый из этих блоков обрабатывает выделения определенного размера и сохраняет все элементы в блоке в виде односвязного списка. Когда вы выделяете суперблок, вы составляете связанный список свободных блоков.
3) Выделение элемента означает A) Проверка, есть ли блок со свободными элементами, обрабатывающими этот размер, и если нет, выделение нового блока из Суперблоки. Б) Удаление предмета из бесплатного списка блока.
4) Освобождение элемента с помощью адреса означает A) поиск суперблока, содержащего адрес (*) B) поиск блока в суперблоке (вычитание начального адреса суперблока и деление на размер блока) C) перемещение объекта обратно в список свободных предметов блока.
1275] Как я уже говорил, этот SBMM очень быстрый, поскольку он работает с производительностью O (1) (*). В реализованной мной версии я использую AtomicSList (аналогичный SLIST в Windows), так что это не только производительность O (1), но также ThreadSafe и LockFree в реализации. Вы могли бы действительно реализовать алгоритм, используя Win32 SLIST, если бы захотели.
Интересно, что алгоритм выделения блоков из суперблоков или элементов из блоков приводит к почти идентичному коду (они оба выделяются O (1) вне свободного Список).
(*) Суперблоки организованы в карту диапазона со средней производительностью O (1) (но потенциальным O (Lg N) для наихудшего случая, где N - количество суперблоков). Ширина карты диапазона зависит от приблизительного знания того, сколько памяти вам понадобится, чтобы получить производительность O (1). Если вы перестреляете, вы потратите немного памяти, но все равно получите производительность O (1). Если вы перестреляете, вы приблизитесь к производительности O (Lg N), но N соответствует количеству суперблоков, а не количеству элементов. Поскольку количество суперблоков очень мало по сравнению с количеством элементов (примерно на 20 двоичных порядков в моем коде), оно не так критично, как остальная часть распределителя.
re понадобится для получения производительности O (1). Если вы перестреляете, вы потратите немного памяти, но все равно получите производительность O (1). Если вы перестреляете, вы приблизитесь к производительности O (Lg N), но N для количества суперблоков, а не для количества элементов. Поскольку количество суперблоков очень мало по сравнению с количеством элементов (примерно на 20 двоичных порядков в моем коде), оно не так критично, как остальная часть распределителя. re понадобится для получения производительности O (1). Если вы перестреляете, вы потратите немного памяти, но все равно получите производительность O (1). Если вы перестреляете, вы приблизитесь к производительности O (Lg N), но N соответствует количеству суперблоков, а не количеству элементов. Поскольку количество суперблоков очень мало по сравнению с количеством элементов (примерно на 20 двоичных порядков в моем коде), оно не так критично, как остальная часть распределителя.