我需要使用以下访问方法定义用户定义对象的集合:
每个对象都有一个主键和一个辅助键(不保证唯一)。将对象添加到集合时,应将其插入某个位置,以便对辅助键值进行排序。 应使用主键或集合中的位置提取或删除每个对象。
实施此系列的最佳方法是什么? (主键和对象的地图将提供一半的访问权限,排序的列表将提供另一半。如何根据我的要求组合这些?)
答案 0 :(得分:2)
您可以轻松地自己编写这样的内容,其中只有(普通)HashMap
只有值的主键,然后是另一个PriorityQueue
对主键的辅助键密钥(作为辅助密钥并不总是唯一的,因此您不能使用Map
类型。)
这是一个完整的,有效的例子:
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
public class MyCollection<T, TPrimaryKey, TSecondaryKey extends Comparable<TSecondaryKey>> {
private HashMap<TPrimaryKey, T> primaryKeyMap;
private List<PrimarySecondaryKeyPair> primarySecondaryKeyList;
public MyCollection() {
primaryKeyMap = new HashMap<TPrimaryKey, T>();
primarySecondaryKeyList = new ArrayList<PrimarySecondaryKeyPair>();
}
public MyCollection(int initialCapacity) {
primaryKeyMap = new HashMap<TPrimaryKey, T>(initialCapacity);
primarySecondaryKeyList = new ArrayList<PrimarySecondaryKeyPair>(initialCapacity);
}
private class PrimarySecondaryKeyPair implements Comparable<PrimarySecondaryKeyPair> {
public TPrimaryKey primaryKey;
public TSecondaryKey secondaryKey;
public PrimarySecondaryKeyPair(TPrimaryKey primaryKey, TSecondaryKey secondaryKey) {
this.primaryKey = primaryKey;
this.secondaryKey = secondaryKey;
}
@Override
public int compareTo(MyCollection<T, TPrimaryKey, TSecondaryKey>.PrimarySecondaryKeyPair o) {
return secondaryKey.compareTo(o.secondaryKey);
}
}
public void put(T object, TPrimaryKey primaryKey, TSecondaryKey secondaryKey) { // put by primaryKey
primaryKeyMap.put(primaryKey, object);
PrimarySecondaryKeyPair keyPair = new PrimarySecondaryKeyPair(primaryKey, secondaryKey);
int insertionPoint = Collections.binarySearch(primarySecondaryKeyList, keyPair);
primarySecondaryKeyList.add((insertionPoint > -1) ? insertionPoint : (-insertionPoint) - 1, keyPair);
}
public T getByPrimaryKey(TPrimaryKey primaryKey) {
return primaryKeyMap.get(primaryKey);
}
public T getByIndex(int index) {
return getByPrimaryKey(primarySecondaryKeyList.get(index).primaryKey);
}
public void deleteByPrimaryKey(TPrimaryKey primaryKey) {
primaryKeyMap.remove(primaryKey);
for (int i = 0; i < primarySecondaryKeyList.size(); i++) {
if (primarySecondaryKeyList.get(i).primaryKey.equals(primaryKey)) {
primarySecondaryKeyList.remove(i);
}
}
}
public void deleteByIndex(int index) {
primaryKeyMap.remove(primarySecondaryKeyList.remove(index).primaryKey);
}
}
这个课程(我认为)可以做你想要的,也不会不必要地存储任何东西。
O(log n)
put()
的时间(为了按二级密钥排序)。
从这个使用的Collections.binarySearch()
方法的JavaDoc :
此方法在
log(n)
时间内运行,随机访问&#34; list(提供接近恒定时间的位置访问)。
(primarySecondaryKeyList
是&#34;随机访问&#34;列表,因为它使用ArrayList
)。
主键获取对象的平均O(1)
时间(如果您的主键类型具有真正的错误哈希函数,则最坏情况变为O(n)
) 。
(见https://en.wikipedia.org/wiki/Hash_table)
O(1)
时间,因为这取决于获取主键(除非您想要将集合中的每个对象存储两次,否则必须这样做)占用两倍的空间。)O(1)
时间。O(n)
最糟糕的情况是通过主键删除(从主键映射中删除很容易,但是必须迭代次键到主键列表)但请注意,如果您的主键只是O(n)
或Integer
,那么最糟糕的情况Long
将永远不会发生,因为它们的哈希函数只是它们的数值,使它们成为非常准确(通常会导致O(1)
s get()
的时间。
以下示例假设您存储String
s , Long
s作为主键,并且 {{1 s作为辅助键。但是,该类是通用的,因此您可以使用任何类型的主键存储任何类型的对象(只需确保它具有合适的Integer
函数!)以及任何对其自身hashCode()
的辅助键(所有原始Comparable
包装器,如Number
,Integer
,Long
等,已经Short
给自己了。
使用默认初始容量初始化:
Comparable
初始容量为50:
MyCollection<String, Long, Integer> myCollection = new MyCollection<String, Long, Integer>();
将字符串MyCollection<String, Long, Integer> myCollection = new MyCollection<String, Long, Integer>(50);
与主键"hello"
和辅助键937234L
放在一起:
2
......其他一切都应该是自我解释的;)
那应该符合您想要的要求和收集类型。
希望它有所帮助。 :)
答案 1 :(得分:1)
(主键和对象的地图将提供一半的访问权限,排序的列表将提供另一半。如何根据我的要求组合这些?)
public class YourCollection{
private Map<UserObject> yourMap;
private List<UserObject> yourList;
public void add(UserObject obj){
yourMap.put(obj.primaryKey, obj);
yourList.add(obj);
//sort list on secondaryKey
}
public UserObject get(String key){
return yourMap.get(key);
}
public UserObject get(int index){
return yourList.get(index);
}
}
这只是基本的shell,但这个想法就在那里。您选择哪种类型的列表和哪种类型的地图取决于您。你可以/也应该在这个类中添加泛型。
编辑 - 此外,对于给定问题,没有最佳方法。你必须考虑不同方法的利弊,并根据你的目标权衡它们。例如,你需要这个来占用最少的内存吗?您是否需要使用最少的CPU周期?您是否需要它才能成为最容易编写和维护的代码?或者你只是想把一些有用的东西放在一起?我实际上并没有要求你回答这些问题,但在考虑这类问题时你应该考虑它们。