Читая документацию Java для списка ADT, говорится:
Интерфейс List предоставляет четыре метода позиционного (индексированного) доступа к элементам списка. Списки (например, массивы Java) отсчитываются от нуля. Обратите внимание, что эти операции могут выполняться во времени, пропорциональном значению индекса для некоторых реализаций (например, класса LinkedList). Таким образом, итерация по элементам в списке обычно предпочтительнее индексирования по нему, если вызывающий не знает реализации.
Что именно это значит? Я не понимаю сделанного вывода.
Ответы:
В связанном списке каждый элемент имеет указатель на следующий элемент:
Чтобы получить доступ
item3
, вы можете ясно видеть, что вам нужно пройти от головы через каждый узел, пока не достигнете item3, поскольку вы не можете прыгать напрямую.Таким образом, если я хочу напечатать значение каждого элемента, если я напишу это:
происходит вот что:
Это ужасно неэффективно, потому что каждый раз, когда вы индексируете, он перезапускается с начала списка и просматривает каждый элемент. Это означает, что ваша сложность заключается в том,
O(N^2)
чтобы просто пройти по списку!Если бы я сделал это:
тогда происходит следующее:
все за один обход, то есть
O(N)
.Теперь, переходя к другой реализации из
List
которыхArrayList
, что одна опирается на простой массив. В этом случае оба вышеуказанных обхода эквивалентны, поскольку массив является непрерывным, поэтому он допускает случайные переходы к произвольным позициям.источник
REVERSE_THRESHOLD
- 18java.util.Collections
дюймов, странно видеть такой ответ без примечания.List l = unknownList(); if (l instanceof RandomAccess) /* do indexed loop */ else /* use iterator/foreach */
Здесь подразумевается ответ:
Связанный список не имеет собственного индекса; для вызова
.get(x)
потребуется реализация списка, чтобы найти первую запись и вызвать.next()
x-1 раз (для O (n) или линейного доступа по времени), где список с поддержкой массива может просто индексировать вbackingarray[x]
в O (1) или с постоянным временем.Если вы посмотрите на JavaDoc для
LinkedList
, вы увидите комментарийтогда как JavaDoc for
ArrayList
имеет соответствующийСвязанный с этим вопрос под названием «Резюме Big-O для Java Collections Framework» есть ответ, указывающий на этот ресурс, «Java Collections JDK6», который может оказаться полезным.
источник
Хотя принятый ответ, безусловно, правильный, могу ли я указать на незначительный недостаток. Цитата Тюдора:
Это не совсем так. Правда в том, что
Источник: Designing for Performance, Google's Android doc.
Обратите внимание, что рукописный цикл относится к индексированной итерации. Я подозреваю, что это из-за итератора, который используется с расширенными циклами for. Это дает незначительную производительность в виде штрафа в структуре, поддерживаемой непрерывным массивом. Я также подозреваю, что это может быть верно для класса Vector.
Мое правило: по возможности используйте расширенный цикл for, а если вы действительно заботитесь о производительности, используйте индексированную итерацию только для ArrayLists или Vectors. В большинстве случаев вы можете даже проигнорировать это - компилятор может оптимизировать это в фоновом режиме.
Я просто хочу указать, что в контексте разработки под Android оба обхода ArrayLists не обязательно эквивалентны . Просто пища для размышлений.
источник
Итерация по списку со смещением для поиска, например
i
, аналогична алгоритму художника Шлемиэля .Источник .
Эта небольшая история может помочь понять, что происходит внутри и почему это так неэффективно.
источник
Чтобы найти i-й элемент
LinkedList
реализация перебирает все элементы вплоть до i-го.Так
источник