Почему классическая реализация Vector (ArrayList для Java-людей) удваивает размер внутреннего массива на каждом расширении вместо того, чтобы увеличивать или увеличивать в четыре раза?Почему векторный массив удваивается?
ответ
При вычислении среднего времени для вставки в вектор необходимо учитывать не растущие вставки и растущие вставки.
вызовов общее количество операций вставки п элементы о всего, а средняя о среднем.
Если вставить п пунктов, и вы растете на фактор по мере необходимости, то есть о общая = п + Σ я [0 < я < 1 + пер A n] операции. В худшем случае вы используете 1/A выделенного хранилища.
Наглядно А = 2 означает, что в худшем случае вы имеете уплотнительное общего = 2n, так уплотнительного среднего представляет собой О (1), а в худшем случае использование 50% выделенное хранение ,
Для большего , у вас есть нижняя уплотнительного общей, но больше впустую хранение.
Для меньшего , о общая больше, но вы не тратите так много места. Пока он растет геометрически, все равно O (1) амортизируется время вставки, но константа будет выше.
Для факторов роста 1,25 (красный), 1,5 (голубой), 2 (черный), 3 (синий) и 4 (зеленый), эти графики показывают эффективность точки и среднего размера (отношение размера/выделенного пространства; лучше) слева и время эффективность (соотношение вставки/операции, лучше) справа для вставки 400 000 предметов. 100% -ная эффективность пространства достигается для всех факторов роста непосредственно перед изменением размера; в случае A = 2 показывает эффективность времени между 25% и 50%, а также экономии пространства около 50%, что хорошо для большинства случаев:
Для автономной работы, таких как Java, массивы равны нулю заполняется, поэтому количество операций для распределения пропорционально размеру массива. Принимая во внимание это дает уменьшает разницу между оценками эффективности времени:
Я подтвердил ваш ответ, но предложил бы изучить, сколько раз каждый элемент в коллекции будет перемещен, когда он набит только от уровня, необходимого для расширения. При коэффициенте роста k только 1/k предметов будут перемещаться даже один раз, 1/k^2 будет перемещаться как минимум дважды, 1/k^3 будет перемещаться три раза и т. Д., Поэтому среднее число раз каждый элемент данных будет перемещаться в 'n' расширениях будет 1/k + 1/k^2 + 1/k^3 + ... 1/k^n, который является ограниченным геометрическим рядом. – supercat
Похоже, что изображения, которые были включены для этого ответа, теперь являются объявлениями для изображений. У вас их все еще есть? – CCovey
Экспоненциально удвоение размера массива (или строки) является хорошим компромиссом между наличием достаточного количества ячеек в массиве и тратой слишком много памяти.
Скажем, мы начинаем с 10 элементами:
1 - 10
2 - 20
3 - 40
4 - 80
5 - 160
Когда мы утроить размер, мы быстро развиваемся
1 - 10
2 - 30
- 90
4 - 270
5 - 810
На практике вы бы расти, может быть, 10 или 12 раз. Если вы утроите, вы, возможно, сделаете это 7 или 8 раз - время выполнения для перераспределения - это несколько раз достаточно мало, чтобы волноваться, но вы, скорее всего, полностью превысите необходимый размер.
Хорошо, но тогда вы можете утверждать, что вектор может просто расшириться до еще одного элемента или расширить на половину количества элементов. Есть ли какая-то особая причина для его удвоения? – TheOne
Если ваш текущий размер составляет 1 000 000 ячеек, то удвоение и копирование кажется очень дорогостоящим. – TheOne
Когда вы удвоитесь, вы гарантированно потратите на ** большинство ** объем памяти, который вы хотите использовать. Точка роста экспоненциально не должна расти вообще, поскольку вы вокруг размера цели. –
Если вы спрашиваете о реализации Java Vector и ArrayList, то это не обязательно удваивается при каждом расширении.
Из Javadoc для Vector:
Каждый вектор пытается оптимизировать управление хранением данных, поддерживая
capacity
иcapacityIncrement
. Емкость всегда не меньше размера вектора; он обычно больше, поскольку, поскольку компоненты добавляются к вектору, хранилище вектора увеличивается в кусках размеромcapacityIncrement
. Приложение может увеличить пропускную способность вектора перед вставкой большого количества компонентов; это уменьшает количество инкрементного перераспределения.
Один из конструкторов для Vector позволяет указать начальный размер и прирост емкости для вектора. Класс Vector также предоставляет ensureCapacity(int minCapacity)
и setSize(int newSize)
для ручной настройки минимального размера вектора и для изменения размера Vector самостоятельно.
Класс ArrayList очень похож:
Каждый
ArrayList
экземпляр имеет емкость. Емкость - это размер массива, используемого для хранения элементов в списке. Он всегда не меньше размера списка. Поскольку элементы добавляются в ArrayList, его емкость растет автоматически. Детали политики роста не указаны за пределами того факта, что добавление элемента имеет постоянную амортизированную временную стоимость.Приложение может увеличить емкость экземпляра
ArrayList
перед добавлением большого количества элементов, используя операцию обеспечения работоспособности. Это может уменьшить количество инкрементного перераспределения.
Если вы спрашиваете об общей реализации вектора, чем выбор увеличения размера и того, насколько это компромисс. Как правило, векторы поддерживаются массивами. Массивы имеют фиксированный размер. Чтобы изменить размер вектора, поскольку он заполнен, вы должны скопировать все элементы массива в новый массив большего размера. Если вы сделаете свой новый массив слишком большим, то вы выделили память, которую вы никогда не будете использовать. Если он слишком мал, может потребоваться слишком много времени, чтобы скопировать элементы из старого массива в новый, более крупный массив - операцию, которую вы не хотите выполнять очень часто.
Нет причин для удвоения по сравнению с три раза или четырехкратным, поскольку все имеют одинаковые профили производительности O. Однако в абсолютном выражении удвоение будет, как правило, более экономичным в нормальном сценарии.
Если вы должны были выделить блок памяти необычного размера, тогда, когда этот блок будет освобожден (либо потому, что вы измените его размер, либо получится GC'd), в памяти будет отверстие необычного размера, которое могло бы вызывают головные боли для менеджера памяти. Поэтому обычно предпочтительнее распределять память по двум. В некоторых случаях основной менеджер памяти будет давать вам только блоки определенных размеров, и если вы запросите странный размер, округлите его до следующего большего размера. Таким образом, вместо того, чтобы запрашивать 470 единиц, возвращая 512 в любом случае, а затем снова изменяя размер, как только вы используете все 470, о которых вы просили, возможно, просто попросите 512 начать с.
Я не согласен с этим ответом. Я не уверен, что он отвечает «почему не на 3 или 4 или 5 темпа роста».Он отвечает на несколько иной вопрос (зачем распределять память на границах полномочий двух)? –
Это, конечно, не та, которую я бы выбрал. Я думал об этом скорее как о дополнительном ответе. В дополнение к другим хорошо объясненным причинам роста скорости, вы тратите ресурсы, если новый массив не является силой двух. Поэтому, учитывая другие аргументы в пользу того, почему более крупный множитель не был бы хорош, единственная сила двух, которая подходит хорошо, равна 2. Она предполагает, что исходный размер также был мощью двух, конечно, но я думаю, что большинство векторов классы стараются это сделать. – kwatford
Справа. «Не согласен», вероятно, было немного сильным :) Кроме того, вы определенно могли бы разработать алгоритм, который обеспечит вам примерно 1,5 рост, который все еще гарантирует, что вы выровнены по словам. Если массив байтов имеет длину 64 байта, вы можете определенно добавить к нему 32 байта и по-прежнему поддерживать выравнивание слов. –
Лично я считаю, что это был произвольный выбор. Мы могли бы использовать base e вместо основания 2 (вместо удвоения только одного размера по (1 + e).)
Если вы собираетесь добавлять большое количество переменных в вектор, тогда было бы выгодно иметь высокая база (для уменьшения количества копий вы будете делать.) С другой стороны, если вам нужно хранить только несколько членов на avg, тогда низкая база будет прекрасной и уменьшит количество накладных расходов, следовательно, ускорит процесс ,
База 2 является компромиссом.
Любое многократное компромиссное решение. Сделайте его слишком большим, и вы потеряете слишком много памяти. Сделайте его слишком маленьким, и вы потратите много времени на перераспределение и копирование. Я думаю, что удвоение существует, потому что оно работает и очень легко реализовать. Я также видел запатентованную STL-подобную библиотеку, которая использует 1.5 как множитель для того же самого - я думаю, его разработчики считали, что удвоение тратит слишком много памяти.
- 1. векторный массив - ошибка сортировки
- 2. Инициализировать векторный массив строк
- 3. Что такое векторный массив?
- 4. Как напечатать векторный массив?
- 5. Почему динамический массив всегда удваивается в 2 раза?
- 6. Почему эта строка текста удваивается?
- 7. C++ - векторный двухмерный массив объектов
- 8. Создать векторный массив символов строк
- 9. Данные Java CSV Строковый массив удваивается
- 10. Наблюдаемые удваивается
- 11. Как обрезать векторный массив символов или строку?
- 12. Почему именно векторный код сломан?
- 13. Почему векторный индекс вне диапазона
- 14. Почему векторный итератор не является неразрешимым?
- 15. Почему мой цикл петли на векторе удваивается?
- 16. Один миллион удваивается
- 17. векторный векторный фиксированный размер
- 18. Как визуализировать векторный массив Галуа в Matlab
- 19. Как убрать векторный контейнер и вернуть массив?
- 20. Передача векторной строки в векторный массив параметров
- 21. Векторный заполняющий массив с использованием numpy
- 22. векторный и c-массив в контексте vecLib
- 23. C++ массив и векторный динамический размер элемента
- 24. счетчик удваивается
- 25. Как положить векторный массив в 1-й массив на C++
- 26. Как преобразовать массив объектов класса в векторный массив?
- 27. Как создать векторный векторный контейнер?
- 28. История браузера удваивается
- 29. Почему размер памяти удваивается при распределении большого количества символов char *?
- 30. Почему этот векторный итератор не увеличивается?
Можно также задаться вопросом, почему не умножить его на 1.5? Или 1.8 и т. Д.? (Можно умножить на 1,5, затем округлить до следующего наибольшего целого числа, скажем.) – Peter
+1 Большой вопрос. –