Java 按插入排序的数据结构,可以得到子集的长度

Java 按插入排序的数据结构,可以得到子集的长度,java,data-structures,linked-list,hashset,treeset,Java,Data Structures,Linked List,Hashset,Treeset,我正在寻找一种Java数据结构,它按插入排序,可以快速查找和删除特定元素,并计算在该元素之后添加的元素数 LinkedHashSet理论上满足这一要求,但接口没有提供任何方法,例如从指定元素开始创建迭代器。我总是需要遍历整个集合 谢谢你的建议 编辑: 好的,我的LinkedHashSet的简单实现(不是真的)就是我的,目前只有我的用例如下,以防万一有人感兴趣。这可以更改为包括实际遍历元素的可能性,而不仅仅是能够计算元素的数量。可能也需要一些重构 public class DoublyLinked

我正在寻找一种Java数据结构,它按插入排序,可以快速查找和删除特定元素,并计算在该元素之后添加的元素数

LinkedHashSet理论上满足这一要求,但接口没有提供任何方法,例如从指定元素开始创建迭代器。我总是需要遍历整个集合

谢谢你的建议

编辑: 好的,我的LinkedHashSet的简单实现(不是真的)就是我的,目前只有我的用例如下,以防万一有人感兴趣。这可以更改为包括实际遍历元素的可能性,而不仅仅是能够计算元素的数量。可能也需要一些重构

public class DoublyLinkedHashSet<T> {
private final Map<T, Entry> map;
private Entry youngestEntry;

public DoublyLinkedHashSet() {
    this.map = new HashMap<T, Entry>();
}

public int size() {
    return map.size();
}

public boolean contains(final T element) {
    return map.containsKey(element);
}

public void add(final T element) {
    final Entry newEntry = new Entry();
    final Entry entryForElement = map.put(element, newEntry);
    boolean entryWasNotAlreadyInSet = entryForElement == null;
    if (entryWasNotAlreadyInSet) {
        newEntry.previousEntry = youngestEntry;
        if (youngestEntry != null) {
            youngestEntry.hasNext = true;
            youngestEntry.nextEntry = newEntry;
        }
    }
    youngestEntry = newEntry;
}

public void remove(final T element) {
    removeEntry(element);
}

public int removeAndGetAmountOfEntriesAfter(final T element) {
    Entry startEntry = removeEntry(element);

    if (startEntry == null) {
        return 0;
    }

    return countAllNextEntries(startEntry);
}

private int countAllNextEntries(final Entry startEntry) {
    int amount = 0;
    Entry currentEntry = startEntry;
    while (currentEntry.hasNext) {
        amount++;
        currentEntry = currentEntry.nextEntry;
    }
    return amount;
}

private Entry removeEntry(final T element) {
    final Entry removedEntry = map.remove(element);

    if (removedEntry == null) {
        return null;
    }

    if (hasPreviousAndNextEntry(removedEntry)) {
        final Entry previousEntry = removedEntry.previousEntry;
        final Entry nextEntry = removedEntry.previousEntry;
        connect(previousEntry, nextEntry);
    } else if (isEndOfList(removedEntry)) {
        final Entry previousEntry = removedEntry.previousEntry;
        resetEndTo(previousEntry);
    } else if (isHead(removedEntry)) {
        final Entry nextEntry = removedEntry.nextEntry;
        resetHeadTo(nextEntry);
    }

    return removedEntry;
}

private boolean hasPreviousAndNextEntry(final Entry entry) {
    return entry.hasPrevious && entry.hasNext;
}

private void connect(final Entry previousEntry, final Entry nextEntry) {
    previousEntry.nextEntry = nextEntry;
}

private boolean isHead(final Entry entry) {
    return !entry.hasPrevious && entry.hasNext;
}

private void resetHeadTo(final Entry entry) {
    entry.previousEntry = null;
    entry.hasPrevious = false;
}

private boolean isEndOfList(final Entry removedEntry) {
    return removedEntry.hasPrevious && !removedEntry.hasNext;
}

private void resetEndTo(final Entry entry) {
    entry.nextEntry = null;
    entry.hasNext = false;
    youngestEntry = entry;
}

private static final class Entry {
    private boolean hasNext;
    private boolean hasPrevious;
    private Entry nextEntry;
    private Entry previousEntry;
}
}
公共类双链接数据库集{
私人最终地图;
私人进入青年中心;
公共双链接数据库集(){
this.map=新的HashMap();
}
公共整数大小(){
返回map.size();
}
公共布尔包含(最后一个T元素){
返回map.containsKey(元素);
}
公共无效添加(最终T元素){
最终条目newEntry=新条目();
最终条目entryForElement=map.put(元素,newEntry);
布尔entryWasNotAlreadyInSet=entryForElement==null;
if(entryWasNotAlreadyInSet){
newEntry.previousEntry=youngestEntry;
if(youngestEntry!=null){
youngestEntry.hasNext=true;
youngestEntry.nextEntry=newEntry;
}
}
youngestEntry=newEntry;
}
公共无效删除(最终T元素){
远程中心(元素);
}
公共int removeAndGetAmountOfEntriesAfter(最终T元素){
进入起点=远程进入(要素);
if(startEntry==null){
返回0;
}
返回countallnextentry(startEntry);
}
私人int Countallnextries(最终输入开始){
整数金额=0;
条目currentEntry=startEntry;
while(currentEntry.hasNext){
金额++;
currentEntry=currentEntry.nextery;
}
退货金额;
}
私人入口远程入口(最终T元素){
最终条目removedEntry=map.remove(元素);
如果(removedEntry==null){
返回null;
}
如果(上一次和下一次(删除条目)){
最终条目previousEntry=removedEntry.previousEntry;
最终条目nextEntry=removedEntry.previousEntry;
连接(上一个条目,下一个条目);
}否则如果(isEndOfList(removedEntry)){
最终条目previousEntry=removedEntry.previousEntry;
resetEndTo(以前的条目);
}否则如果(isHead(删除条目)){
最终条目nextEntry=removedEntry.nextEntry;
重置头至(下一个月);
}
返回删除的条目;
}
私有布尔值hasPreviousAndNextEntry(最终条目){
return entry.hasPrevious&&entry.hasNext;
}
专用void connect(上一个最终条目,下一个最终条目){
previousEntry.nextEntry=nextEntry;
}
专用布尔isHead(最终条目){
return!entry.hasPrevious&&entry.hasNext;
}
私人作废重置抬头(最终分录){
entry.previousEntry=null;
entry.hasPrevious=false;
}
私有布尔值isEndOfList(最终条目removedEntry){
返回removedEntry.hasPrevious&!removedEntry.hasNext;
}
私人作废重置结束(最终分录){
entry.nextEntry=null;
entry.hasNext=false;
youngestEntry=入口;
}
私有静态最终类条目{
私有布尔hasnet;
私有布尔值;
私人进入;
私人进入优先进入;
}
}

我想你是在找一个,或者你为什么不能使用它

public int removeAndCount(Object o){
    int i = list.indexOf(o);
    list.remove(o);
    return list.size() - i;
}

你应该能够使用一个。它提供了一种方法,可以满足您的需要


您可以按插入顺序对它们进行排序,方法是向对象中添加一个序列号并进行排序。

有一个散列集合来保存您的对象,并在对象旁边维护一个列表(例如,这就是LinkedHashMap所做的,这对您来说非常好,但它隐藏了它的内部列表)。如果经过哈希处理的集合的元素在列表中具有相同元素的索引,则只需跳转到给定索引处的列表,并轻松地遍历其其余部分。我认为您提到的所有操作都需要次线性时间才能使用此解决方案运行,但不能更快(对~n个元素的迭代总是需要~n个时间)

具有HashMap和LinkedList的示例解决方案:

查找:
HashMap.get(key)
保存列表中的索引,
key
是您的元素。对数(n)时间

remove:
LinkedList.remove(HashMap.get(key))
,HashMap.remove(key),元素就消失了。对数(n)时间

迭代:

for (i=HashMap.get(key); i<LinkedList.size(); i++){
     //etc
}

for(i=HashMap.get(key);它的效率不够,在查找时是线性的,对于散列集合可能是对数的。是的,但列表跟踪索引,而不是集合。我认为这正是他需要的。问题在于,这不仅是indexOf(Object)线性,add也是。获取列表的剩余长度显然是常数时间,但这不会超过我的例子中的许多add调用。add(obj)是常数时间,只有add(obj,x)不是。Ups,你是对的。indexOf和remove与log(n)相比仍然是线性的如果我真的能够使用LinkedHashSet。LinkedHashSet有你需要的一切,但我担心它对它的客户是隐藏的。别让我哭;-)我有一段时间确信这是个好主意,然后又有一段时间没有考虑它。但是:这样,如果我已经保存了对象的序列号,我只能在log(n)time中删除一个元素,因为它是按序列号排序的。我的第一个想法是添加一个HashMap来查找带有对象哈希的序列号。这看起来很傻。我想我将只实现我自己的SingleyLinkedHashSet,因为我可以将大多数方法委托给哈希