在JRE中使用什么算法将ArrayList <t>转换为LinkedHashSet <t>

时间:2018-09-22 13:56:08

标签: java algorithm hashmap set linkedhashset

我想从list获得list的唯一元素,其中元素重复,应该保持列表中元素的顺序。

要实现这一点,我可以编写一个像这样的算法:

private ArrayList<T> getUnique(ArrayList<T> list)
{
    // maintain a hashmap of numbers and a uniqueList to be returned(ArrayList<T>)
    // Add element in result list and the hashmap if the element isn't already present in the hashmap, else just add in the hashmap

    HashMap<T, Boolean> map = new HashMap<>();
    ArrayList<T> uniqueList = new ArrayList<>();

    for (T t: list)
    {
        if (map.get(t) == null)
        {
            // t wasn't present so, adding them in map as well as in the list
            map.put(t, true);
            uniqueList.add(t);
        }
    }
    return uniqueList;
}

此算法将花费O(n)的时间,并有O(n)的额外空间(用于HashMap)。

或者简单地说,我可以使用以下语法:

Set<T> set = new LinkedHashSet<>(list);

以上Java语法用于从set获取list的唯一元素,其出现顺序与list相同。 然后将此列表转换为列表。 (ArrayList<T> uniqueList = new ArrayList<>(set);

我假设这里的时间复杂度也是O(n)。我想知道Java用于什么算法。

我看到该类名为LinkedHashSet,所以我认为他们可能使用一些LinkedList概念来实现这一目标,因此我研究了源代码,并发现了这些东西:

  1. LinkedHashSet.java中,构造函数如下:

143: public LinkedHashSet(Collection<? extends T> c) 144: { 145: super(c); 146: } here是来源。

  1. 因此,我查看了父类的构造函数,即HashSet,发现:

public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); }

  1. 接下来,我搜索了addAll方法,我在AbstractCollection类(它是HashSet类的祖父母)中找到了它,该函数的定义是:

public boolean addAll(Collection<? extends E> c) { boolean modified = false; for (E e : c) if (add(e)) modified = true; return modified; }

这正在呼叫add,就像:

public boolean add(E e) { throw new UnsupportedOperationException(); } here

我听不懂。他们为此任务使用什么算法?

3 个答案:

答案 0 :(得分:3)

为解决您的困惑,add中的HashSet方法如下:

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

请注意,LinkedHashSet扩展了HashSet扩展了AbstractSet扩展了AbstractCollection


总而言之,使用的算法是:

    for (E e : c)
        add(e);

对于O(N)LinkedHashSet,因为add的{​​{1}}的平均复杂度是LinkedHashSet

答案 1 :(得分:3)

对于寻找整个故事的人

基于LinkedHashSetHashSetLinkedHashMap的源代码。 构造一个null并将 .... Bitmap bitmap; private Response networkFetchAsset(String path, String[] params){ OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url(myURL) .build(); try { Response response = client.newCall(request).execute(); System.out.print(response); InputStream inputStream = response.body().byteStream(); bitmap = BitmapFactory.decodeStream(inputStream); System.out.print(bitmap); try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } return response; } catch (Exception e) { e.printStackTrace(); } return null; } 扩展到其他集合时(LinkedHashSet.java第143行),

LinkedHashSet

哪个会调用(HashSet.java第136行):

HashSet

然后调用(HashSet.java第122行):

public LinkedHashSet(Collection<? extends T> c)  
{  
  super(c);  
}

由于public HashSet(Collection<? extends T> c) { this(Math.max(2 * c.size(), HashMap.DEFAULT_CAPACITY)); addAll(c); } 中的public HashSet(int initialCapacity, float loadFactor) { map = init(initialCapacity, loadFactor); } 方法已被覆盖

init

后盾LinkedHashSetHashMap<T, String> init(int capacity, float load) { return new LinkedHashMap<T, String>(capacity, load); }

根据LinkedHashMap的Java文档

  

此类提供所有可选的Map操作,并允许空元素。像HashMap一样,它假定基本功能(添加,包含和删除)提供恒定时间性能,假设哈希函数将元素正确地分散在存储桶中。由于维护链表的额外费用,性能可能会略低于HashMap,但有一个例外:对LinkedHashMap的集合视图进行迭代需要的时间与地图的大小成正比,而无论其容量如何。在HashMap上进行迭代可能会更加昂贵,所需的时间与其容量成正比。

map的{​​{1}}方法是

LinkedHashMap
因此,构造的平均时间复杂度为O(n)。 对于该算法,我认为您可以阅读LinkedHashMap的代码以了解详细信息。 进一步阅读How is the internal implementation of LinkedHashMap different from HashMap implementation?HashSet vs LinkedHashSet

答案 2 :(得分:2)

这是LinkedHashSet的构造函数:

public LinkedHashSet(Collection<? extends E> c) {
        super(Math.max(2*c.size(), 11), .75f, true);
        addAll(c);
    }

这是java.util.AbstractCollection中的addAll函数:

public boolean addAll(Collection<? extends E> c) {
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }

这是java.util.HashSet中的添加函数:

public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

easy-peasy(如果使用Intellij查找功能的来源)。