【问题标题】:Is there a list backed by a Map?是否有地图支持的列表?
【发布时间】:2017-06-21 00:33:13
【问题描述】:

我在 Swing TreeList 中显示的列表中有 100k 项。见 jide-demo 中的 AutoFilterTreeTableDemo https://www.jidesoft.com/products/download.htm

过滤时需要很长时间才能扩展节点。

在分析时,Vector.indexOf() 大约需要 20 秒。我将它切换到 ArrayList 并花费了大约 5 秒。

然后我将列表缓存为Map<Row, Integer>,其中整数是列表中的索引。这将过滤减少到 ~0.2s。

但是,如果我在中间某处添加一行,我必须重建地图,因为列表的索引会发生变化。

是否有使用映射来支持列表索引的数据结构?还是我必须自己处理?

或者,是否有一个普通的 List 具有非常快的 indexOf 时间?我不介意为此牺牲插入/删除时间略微

第三种选择是我可以使用更优化的可过滤 Swing 网格。

编辑:代码 sn-p:

    private Map<Row, Integer> rowLookup = new ConcurrentHashMap<Row, Integer>();

    @Override
    public int getRowIndex(Row row) {
        if(rowLookup.isEmpty()) {
            List<Row> existingRows = getRows();
            for(int i = 0; i < existingRows.size(); i++) {
                Row mappingRow = existingRows.get(i);
                rowLookup.put(mappingRow, i);
            }
        }
        if(row == null) {
            return -1;
        } else {
            Integer lineNumber = rowLookup.get(row);
            if(lineNumber == null) {
                lineNumber = -1;
            }
            return lineNumber;
        }
    }

【问题讨论】:

  • ArrayList 具有比哈希映射更快的随机访问(通过索引访问)。 (顺便说一句,您没有发布您使用的地图实现)。
  • @MouseEvent 但索引需要朝另一个方向发展:行到索引,而不是索引到行。
  • 您所描述的由地图支持的列表是否不支持重复条目并因此是一个集合?
  • 你可以用来展示的最抽象的数据结构是什么?例如,只是 Iterable 的东西会起作用吗?
  • 根据您的要求,ArrayList 有 O(1) 插入和 O(n) indexOf。 HashMap 有 O(n) 插入和 O(1) indexOf。如果您要创建一个将平衡树(Node 缓存其左子树的大小)和 HashMap> 配对在一起的数据结构,您可以获得 O(log n) 插入和O(log n) indexOf (O(1) 使用 HashMap 找到内部节点,然后 O(log n) 在您向上走时添加左子树大小)。这是否是一个合理的权衡取决于您的情况。

标签: java list arraylist


【解决方案1】:

我认为您可能已经接近最佳解决方案。你有两个相互矛盾的需求:

  1. 您希望能够随机插入项目
  2. 您希望能够根据固定索引访问这些项目

对于 (1),您通常会使用地图或链接列表之类的东西

对于 (2),您将使用数组

(1) 与 (2) 冲突的原因是,当您执行 (1) 时,您必须更新 每个 后续项目,以便更新其索引。我不认为你会找到一个通用的数据结构来做到这一点,因为它不能有效地完成。

我想如果我是你,除了重组问题(我认为目前不可能)之外,我会做你正在做的事情。

但是,与其将地图视为整体,不如将其用作缓存。

当您进行查找时,再次检查以确保索引匹配,如果它没有从映射中清除条目;找到正确的值;然后更新地图,例如

public int getRowIndex(Row row) {

    Integer index = rowLookup.get(mappingRow);

    List<Row> existingRows = getRows();

    if (index != null) {

        int i = index.intValue();

        if (i < existingRows.size() && row == existingRows.get(i)) {
            return i;
        }

        rowLookup.remove(i);
    }

    /* Otherwise we'll have to look it up the slow way */
    int i = existingRows.indexOf(row);
    rowLookup.put(row, i);
    return i;
}

抱歉,没有尝试编译,这只是为了说明

您可能希望将此与另一个定期运行的函数配对,以重建整个缓存。

【讨论】:

    【解决方案2】:

    不完全是您正在寻找的,但它可以被视为您问题的替代解决方案:org.apache.commons.collections.list.TreeList indexOf 方法的性能并不优于 ArrayList 实现,但对于您的用例,我认为它是可以接受的。

    此列表实现在内部利用树结构来确保所有插入和删除都是 O(log n)。

    下表是从他们的文档中获得的,用于衡量与其他 List 实现相比的性能。缺点是它会消耗更多的内存:

     *              get  add  insert  iterate  remove
     * TreeList       3    5       1       2       1
     * ArrayList      1    1      40       1      40
     * LinkedList  5800    1     350       2     325
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-06
      • 1970-01-01
      • 2010-12-11
      • 2015-03-19
      相关资源
      最近更新 更多