如何使用索引进行O(1)随机访问的排序集

时间:2012-01-02 13:48:53

标签: java list sorting

需要一个字符串集合,其中插入的元素需要排序,也可以不重复,可以通过索引检索。

  • 我可以使用TreeSet删除重复内容并对其中的所有内容进行排序 订单但无法通过索引检索。检索通过 index,我可以为它生成ArrayListaddAll个元素,但是这个 addAll需要很多时间。

  • 我可以使用ArrayList,插入必填项,然后通过其他方法删除重复项,然后使用Collections.sort方法对元素进行排序。

但问题是,所有这些都需要时间,是否有任何直接的方法来实现这一点,一个集合 - 排序,非重复,通过索引进行O(1)随机访问。

10 个答案:

答案 0 :(得分:3)

在commons集合中有一个名为SetUniqueList的数据类型,我认为它完全满足您的需求。看看:

https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/list/SetUniqueList.html

答案 1 :(得分:2)

您可以使用第二个想法:

  

我可以使用ArrayList,插入required,然后删除一些重复项   其他方法,然后使用Collections.sort方法对元素进行排序。

但不是在排序之前删除重复项,而是先排序ArrayList,然后所有重复项都在连续的位置,之后可以在一次传递中删除。

此时,您的方法都具有相同的整体复杂度:O(N * logN),值得注意的是,无论如何都无法获得比此更快的排序序列(无需额外利用有关值的一些知识)。< / p>

答案 2 :(得分:2)

这里真正的问题是OP 没有告诉我们真正的问题。所以很多人都在猜测数据结构并在没有真正思考的情况下发布答案。

真正的症状,正如评论中所述的OP,是将字符串放在TreeSet中需要700ms,而另一个 700 ms来复制该TreeSet进入ArrayList。显然,程序没有做OP认为的那样,因为副本最多只需要几微秒。实际上,在我的古老Thinkpad上运行的下面的程序只需要360ms来创建100,000个随机字符串,将它们放在TreeSet中,然后将TreeSet复制到ArrayList中。

那就是说,OP选择了答案(两次)。也许如果/当OP决定考虑真正的问题时,这个SSCCE的例子将会有所帮助。它是CW,所以随时编辑它。


import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.TreeSet;


public class Microbench
{
    public static void main(String[] argv)
    throws Exception
    {        
        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
        long start = threadBean.getCurrentThreadCpuTime();
        executeTest();
        long finish = threadBean.getCurrentThreadCpuTime();
        double elapsed = (finish - start) / 1000000.0;
        System.out.println(String.format("elapsed time = %7.3f ms", elapsed));
    }


    private static List<String> executeTest()
    {
        String[] data = generateRandomStrings(100000);

        TreeSet<String> set = new TreeSet<String>();
        for (String s : data)
            set.add(s);

        return new ArrayList<String>(set);
    }


    private static String[] generateRandomStrings(int size)
    {
        Random rnd = new Random();
        String[] result = new String[size];
        for (int ii = 0 ; ii < size ; ii++)
            result[ii] = String.valueOf(rnd.nextLong());
        return result;
    }
}

答案 3 :(得分:1)

性能取决于元素的添加频率以及索引访问它们的频率。

  

我可以使用TreeSet删除重复项并按顺序对所有内容进行排序,但无法通过索引检索。通过索引检索,我可以生成arraylist和addall元素,但是这个addAll需要很多时间。

每次要将SortedSet作为List(即元素索引)访问时,

List.addAll(yourSortedSet)将至少占用O(n)时间和空间。

  

我可以使用ArrayList,插入required,然后通过其他方法删除重复项,然后使用Collections.sort方法对元素进行排序。

每次你想要列表的排序视图时,

排序肯定会超过O(n)。

另一个解决方案

如果您没有经常通过索引获取,那么按以下方式执行此操作会更有效:

只需将String存储在SortedSet中,可以扩展TreeSet并提供/实现您自己的get(int i)方法,在此方法中迭代直到第i个元素并返回该元素。在最坏的情况下,这将是O(n),否则要小得多。这样,您执行任何比较,转换或复制字符串。不需要额外的空间。

答案 4 :(得分:0)

我不确定,你测试地图吗?我的意思是在TreeMap中使用你的字符串作为键。

在Map中,键是O(1)来查找其位置(哈希值)。 TreeMap的keySet将在TreeMap中返回一组有序的键。

这是否符合您的要求?

答案 5 :(得分:0)

如果您在操作的开始和结束时绑定到List,请在元素之后将其转换为带有“copy”构造函数(或Set)的addAll填充,这将删除重复项。如果您将其转换为具有适当TreeSet的{​​{1}},它甚至会对其进行排序。然后,您可以将其转换回Comparator

答案 6 :(得分:0)

使用Hashmap,您将解决唯一值的问题,并通过一些排序方法对其进行排序。如果可以使用quicksort。

答案 7 :(得分:0)

可能使用LinkedList(它比arraylist占用更少的内存)使用boolean方法确定该元素是否已经在列表中以及QuickSort算法。 java中的所有结构都必须以某种方式排序并保护我免受重复,所以一切都需要时间......

答案 8 :(得分:0)

有两种方法可以使用LinkedMap,其中map中的每个元素都是唯一的,或者自己扩展list和override方法add

import java.util.ArrayList;

public class MyList<V> extends ArrayList<V>{

    private static final long serialVersionUID = 5847609794342633994L;

    public boolean add(V object) {
        //make each object unique
        if(contains(object)){
            return false;
        }

        //you can make here ordering and after save it at position 

        //your ordering here

        //using extended method add
        super.add(yourposition,object);
    }
}

答案 9 :(得分:0)

我还遇到了在TreeMap中的某个位置找到元素的问题。我用权重增强了树,允许通过索引访问元素并在索引处查找元素。 该项目称为索引树映射http://code.google.com/p/indexed-tree-map/。在有序映射中的索引处查找元素或元素的索引的实现不是基于线性迭代,而是基于树二进制搜索。更新树的权重也基于垂直树上升。所以没有线性迭代。