我想从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
概念来实现这一目标,因此我研究了源代码,并发现了这些东西:
LinkedHashSet.java
中,构造函数如下:
143: public LinkedHashSet(Collection<? extends T> c)
144: {
145: super(c);
146: }
here是来源。
HashSet
,发现:
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
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。
我听不懂。他们为此任务使用什么算法?
答案 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)
基于LinkedHashSet,HashSet,LinkedHashMap的源代码。
构造一个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
后盾LinkedHashSet
是HashMap<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查找功能的来源)。