Эффективно извлекать последний вставленный элемент в LinkedHashSet [дублировать]

Согласно Javadoc LinkedHashSet, он будет сохраняйте порядок вставки вставляемых элементов, используя внутренне двусвязный список.

он поддерживает двусвязный список, охватывающий все его записи. Этот связанный список определяет порядок итераций, то есть порядок, в котором элементы были вставлены в набор (порядок вставки).

Если я хочу получить первый вставленный элемент, я могу использовать такой код:

linkedHashSet.iterator().next()

Это даст мне первый вставленный элемент в наборе в O (1).

Я пытаюсь решить проблему, которая требует от меня доступа к самому последнему вставленному элементу в набор в O (1), и предположим, что в набор не будет вставлен какой-либо дублированный элемент. Например,

linkedHashSet.add(2); // the most recent inserted element in the set is 2
linkedHashSet.add(3); // the most recent inserted element in the set is 3
linkedHashSet.add(5); // the most recent inserted element in the set is 5
linkedHashSet.remove(5); // the most recent inserted element in the set is 3 because 5 is removed and not in the set now

Поскольку это двусвязный список в наборе, кажется, что самый последний элемент должен быть последним в двусвязном списке и должен иметь возможность доступа в O (1), если есть какой-то API для его получения.

Мой вопрос: есть ли способ сделать это в JDK или мне нужно создать свой собственный ReversedIteratingLinkedHashSet для этого?

По сути, я пытаюсь найти структуру данных Set с временной сложностью O (1) для всех операций, включая: вставку / удаление / поиск / проверку самого последнего вставленного элемента в наборе. Встроенный LinkedHashSet кажется хорошо сочетающимся с очень небольшой внутренней модификацией, но я не уверен, можно ли это сделать с помощью API класса JDK по умолчанию или нет.

Примечание: я проверил исходный код JDK и знаю, что LinkedHashSet внутренне реализован с помощью LinkedHashMap, и если есть какое-либо решение, которое могло бы использовать LinkedHashMap для доступа к самому последнему вставленному элементу в O (1), это тоже полезно для меня.

Большое спасибо.


person nybon    schedule 25.07.2013    source источник
comment
Просмотрите мой учебник Внутренняя жизнь LinkedHashMap, чтобы лучше узнать LinkedHashSet, потому что последний является лишь оболочкой первого   -  person Volodymyr Levytskyi    schedule 30.07.2013
comment
Я бы рекомендовал использовать здесь LinkedHashMap. Потому что после вставки сопоставления вы можете очень быстро получить его по ключу. В любом случае LinkedHashSet - это LinkedHashMap.   -  person Volodymyr Levytskyi    schedule 30.07.2013


Ответы (1)


К сожалению, похоже, что нет прямого / чистого способа доступа к последнему добавленному элементу в LinkedHashSet (или LinkedHashMap) в O (1).

Чистым способом было бы преобразовать набор в массив и получить доступ к последнему элементу, но это было бы O (n).

Грязным способом было бы использовать отражение для доступа к внутренней хэш-карте, записи заголовка карты и, наконец, предшественнику записи (before).

person Thomas    schedule 25.07.2013
comment
Спасибо, что сообщили мне грязный способ сделать это, и в итоге я написал свой собственный вариант LinkedHashSet. - person nybon; 27.07.2013
comment
@VolodymyrLevytskyi, помимо ваших манер (называя кого-то лжецом), вы должны доказать свои утверждения. При итерации последний вставленный элемент будет последним в порядке, если только у вас нет собственной реализации, которая делает это наоборот. - person Thomas; 30.07.2013
comment
Прости! По правде говоря, последний добавленный элемент находится во главе связанного списка и является последним при повторении ... - person Volodymyr Levytskyi; 30.07.2013
comment
@VolodymyrLevytskyi Я взглянул на код (в JDK 6, но я сомневаюсь, что было много изменений), и это не похоже на правду. Запись header всегда будет пустой записью, и любая новая запись будет добавляться перед заголовком. Однако, поскольку список имеет двойную связь, нет настоящей главы, кроме элемента, на который имеется ссылка как header, и эта ссылка, похоже, вообще не изменилась. - person Thomas; 30.07.2013
comment
Заголовок переменной ссылается на первый вставленный элемент по его переменной after и к последнему добавленному элементу по его переменной before. Заголовок переменной используется всякий раз, когда вы повторяете связанный список, потому что его переменная after ссылается на первую вставленную запись. Заголовок переменной также имеет свою переменную до, которая используется всякий раз, когда создается новая запись. header.before ссылается на последнюю вставленную запись, чтобы связать будущую запись с текущей, содержащей связанный список. Покройте мой учебник, и все станет ясно. Я торопился и ошибся с порядком итераций. - person Volodymyr Levytskyi; 30.07.2013
comment
@VolodymyrLevytskyi, пожалуйста, прочтите мой ответ еще раз, это именно то, что я сказал: возьмите голову (хорошо, она называется header), затем ее предшественницу (before), которая является последней вставленной записью. - person Thomas; 30.07.2013