通过插入排序的数据结构可以获得子集的长度

时间:2015-01-16 12:09:15

标签: java data-structures linked-list hashset treeset

我正在寻找Java中的数据结构,它通过插入排序,可以快速查找和删除特定元素,并计算在此元素之后添加的元素数量。

LinkedHashSet 理论上满足此要求,但接口不提供任何方法,例如从指定元素开始创建 Iterator 。我总是要遍历整个集合。

感谢您的任何建议。

修改 好吧,我的简单实现(不是真的)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;
}
}

3 个答案:

答案 0 :(得分:3)

您应该可以使用SortedSet。它提供了tailSet方法,可以满足您的需求。

您可以通过向对象添加序列号并对其进行排序来对插入顺序进行排序。

答案 1 :(得分:1)

我认为您正在寻找ArrayList,或者您有什么理由不能使用它?

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

答案 2 :(得分:1)

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

使用HashMap和LinkedList的示例解决方案:

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

删除:LinkedList.remove(HashMap.get(key)),HashMap.remove(键),你的元素消失了。 log(n)时间

迭代:

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

你可能也需要打开LinkedList,因为.get(index)我打赌需要线性时间才能运行。