Сводка ArrayList
с ArrayDeque
предпочтительны в [1 147] многие [еще 1147] примеры использования, чем LinkedList
. Если Вы не sure — только запустите с ArrayList
.
LinkedList
и ArrayList
две различных реализации интерфейса List. LinkedList
реализации это с двунаправленным связанным списком. ArrayList
реализации это с динамично изменяющим размеры массивом.
Как со стандартным связанным списком и операциями над массивом, различные методы будут иметь различное алгоритмическое время выполнения.
get(int index)
, O (n) (с [1 149] шаги n/4 в среднем) add(E element)
, O (1) add(int index, E element)
O (n) (с [1 152] шаги n/4 в среднем), но O (1) когда index = 0
<---, который основное преимущество [1 113] remove(int index)
O (n) (с [1 155] шаги n/4 в среднем) Iterator.remove()
, O (1) . <---, который основное преимущество [1 116] ListIterator.add(E element)
O (1) , Это - одно из основных преимуществ [1 118] Примечание: для Многих операций нужно шаги n/4 в среднем, постоянный количество шагов в лучшем случае (например, индекс = 0), и , шаги n/2 в худшем случае (середина списка) глоток>
get(int index)
O (1) <---основное преимущество [1 121] add(E element)
O (1) амортизировано, но O (n) худший случай, так как массив должен быть изменен и скопировал add(int index, E element)
, , O (n) (с [1 165] шаги n/2 в среднем) remove(int index)
, O (n) (с [1 167] шаги n/2 в среднем) Iterator.remove()
, O (n) (с [1 169] шаги n/2 в среднем) ListIterator.add(E element)
O (n) (с [1 171] шаги n/2 в среднем) Примечание: для Многих операций нужно шаги n/2 в среднем, постоянный количество шагов в лучшем случае (конец списка), шаги n в худшем случае (запустите списка) , глоток>
LinkedList
допускает постоянно-разовые вставки или удаления итераторы использования , но только последовательный доступ элементов. Другими словами, можно обойти список вперед или назад, но нахождение положения в списке занимает время пропорциональное размеру списка. Javadoc заявляет "операции, что индекс в список пересечет список с начала или конца, какой бы ни ближе" , таким образом, те методы O (n) ( шаги n/4) в среднем, хотя O (1) для [1 128].
ArrayList
, с другой стороны, позволяют быстро случайный доступ для чтения, таким образом, можно захватить любой элемент в постоянное время. Но добавление или удаление отовсюду, но конец требуют, чтобы смещение всех последних элементов, или сделало открытие или заполнило разрыв. Кроме того, если Вы добавляете больше элементов, чем способность основного массива, новый массив (1.5 раза размер) выделяется, и старый массив копируется в новый, таким образом добавление к ArrayList
O (n) в худшем случае, но постоянно в среднем.
Так в зависимости от операций Вы намереваетесь сделать, необходимо выбрать реализации соответственно. Итерация по любому виду Списка является практически одинаково дешевой. (Выполняющий итерации по ArrayList
технически быстрее, но если Вы не делаете что-то действительно чувствительное к производительности, Вы не должны волноваться об этом - они - оба константы.)
основные преимущества использования LinkedList
возникают, когда Вы снова используете существующие итераторы, чтобы вставить и удалить элементы. Эти операции могут тогда быть сделаны в [1 181] O (1) путем изменения списка локально только. В списке массива остаток от массива должен быть , переместился (т.е. скопировал). С другой стороны, ища в LinkedList
средства, переходящие по ссылкам в [1 183] O (n) ( шаги n/2) для худшего случая, тогда как в ArrayList
желаемое положение может быть вычислено математически и получено доступ в [1 185] O (1) .
Другое преимущество использования LinkedList
возникает, когда Вы добавляете или удаляете из заголовка списка, так как те операции O (1) , в то время как они O (n) для [1 136]. Обратите внимание, что ArrayDeque
может быть хорошая альтернатива [1 138] для добавления и удаления от главы, но это не List
.
кроме того, если у Вас есть большие списки, имеют в виду, что использование памяти также отличается. Каждый элемент LinkedList
имеет больше служебное, так как указатели на следующие и предыдущие элементы также хранятся. ArrayLists
не имеют этих издержек. Однако ArrayLists
поднимают столько памяти, сколько выделяется для способности, независимо от того, были ли элементы на самом деле добавлены.
начальная способность по умолчанию ArrayList
довольно мала (10 от Java 1.4 - 1.8). Но так как конкретная реализация является массивом, массив должен быть изменен, если Вы добавляете много элементов. Для предотвращения высокой стоимости изменения размеров, когда Вы знаете, что собираетесь добавить много элементов создайте ArrayList
с более высокой начальной мощностью.
Для этого есть функции, но они могут зависеть от того, какой язык вы используете. Два примера:
если у вас есть доступ к приличной математической библиотеке C99, вы можете использовать nextafter
(и его варианты с плавающей запятой и long double, nextafterf
и nextafterl
]); или семейство nexttoward
(которое принимает длинный двойной аргумент).
если вы пишете Fortran, у вас будет ближайший
внутренний доступный
Если вы не можете получить доступ они прямо с вашего языка, вы также можете посмотреть, как они реализованы в свободном доступе, например этот .
Я не уверен, что понимаю вашу проблему. Несомненно, стандарт IEEE полностью единообразен ? Например, посмотрите этот отрывок из статьи википедии для чисел с двойной точностью.
3ff0 0000 0000 0000 = 1
3ff0 0000 0000 0001 = 1.0000000000000002, the next higher number > 1
3ff0 0000 0000 0002 = 1.0000000000000004
Что не так с простым увеличением младшего бита, в двоичном или шестнадцатеричном представлении?
Что касается специальных чисел (бесконечность, NaN и т. д.), они хорошо определены, и их не так много. Пределы определены аналогичным образом.
Поскольку вы, очевидно, изучили это, я полагаю, что у меня не тот конец палки. Если этого недостаточно для решения вашей проблемы, не могли бы вы прояснить, чего вы хотите достичь? Какая у вас здесь цель?
хотите достичь? Какая у вас здесь цель? хотите достичь? Какая у вас здесь цель?Да, способ есть. В C #:
public static double getInc (double d)
{
// Check for special values
if (double.IsPositiveInfinity(d) || double.IsNegativeInfinity(d))
return d;
if (double.IsNaN(d))
return d;
// Translate the double into binary representation
ulong bits = (ulong)BitConverter.DoubleToInt64Bits(d);
// Mask out the mantissa bits
bits &= 0xfff0000000000000L;
// Reduce exponent by 52 bits, so subtract 52 from the mantissa.
// First check if number is great enough.
ulong testWithoutSign = bits & 0x7ff0000000000000L;
if (testWithoutSign > 0x0350000000000000L)
bits -= 0x0350000000000000L;
else
bits = 0x0000000000000001L;
return BitConverter.Int64BitsToDouble((long)bits);
}
Увеличение можно складывать и вычитать.
Как говорит Торстен С., это можно сделать с помощью класса BitConverter
, но его метод предполагает, что метод DoubleToInt64Bits
возвращает внутреннюю байтовую структуру double
, а это не так. Целое число, возвращаемое этим методом, на самом деле возвращает количество представимых двоек от 0 до ты. Т.е. наименьшая положительная двойка представлена 1, следующая по величине двойка - 2 и т.д. и т.п. Отрицательные числа начинаются с long.MinValue
и уходят от 0d.
Поэтому вы можете сделать что-то вроде этого:
public static double NextDouble(double value) {
// Get the long representation of value:
var longRep = BitConverter.DoubleToInt64Bits(value);
long nextLong;
if (longRep >= 0) // number is positive, so increment to go "up"
nextLong = longRep + 1L;
else if (longRep == long.MinValue) // number is -0
nextLong = 1L;
else // number is negative, so decrement to go "up"
nextLong = longRep - 1L;
return BitConverter.Int64BitsToDouble(nextLong);
}
Это не касается Infinity
и NaN,
но вы можете проверить их и работать с ними как угодно, если вас это беспокоит.