假设我有一个列表A需要看起来与列表B完全相同.B所有的对象除了A之外没有必要添加到A.而A所有但没有B的对象需要从A中删除。
我之所以需要这个,是因为我有一个我正在保存到文件的播放器ArrayList。每次更新播放器的属性时,我都会通过调用一个查看播放器的ArrayList并保存它的方法将更改保存到文件中。这是有效的,因为ArrayList具有对玩家的引用。
但是,每当我在列表中搜索播放器时,我首先通过读取其存储的文件来更新列表。这将使用全新对象替换所有引用。执行此操作后,如果我对以前提取的用户进行了更改并尝试保存它。播放器的新实例将被保存,而不是我进行更改的实例。
会想出一个好的算法来使列表等于另一个解决方案吗?或者是否有更好的方法来更新整个列表,同时保持在那里使用引用?
更新:更新的解决方案,在O(nlogm)时间内运行。遍历目标中的每个元素,在源中搜索它。如果找到,则从源中删除。如果没有,则从目的地移除。然后将源中的剩余元素添加到目标。列表当然需要进行排序,但是我从文件中获取的列表已经被排序了,因为我按照我的添加进行排序。
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class CopyList {
public static void copyList(List dest, List src) {
copy(dest, src);
// the remaining elements in src list will be those that were originally
// in src but not in dest and so they need to be added
dest.addAll(src);
}
public static void copyList(List dest, List src, Verify v) {
copy(dest, src);
// the remaining elements in src list will be those that were originally
// in src but not in dest and so they need to be added
addAll(dest, src, v);
}
public static void copyList(List dest, List src, Comparator c) {
copy(dest, src, c);
// the remaining elements in src list will be those that were originally
// in src but not in dest and so they need to be added
dest.addAll(src);
}
public static void copyList(List dest, List src, Comparator c, Verify v) {
copy(dest, src, c);
// the remaining elements in src list will be those that were originally
// in src but not in dest and so they need to be added
addAll(dest, src, v);
}
private static void copy(List dest, List src) {
// go through dest list to search if every element is in the new list
// travel backwards through dest because we will be removing elements from it
for(int i = dest.size()-1; i >= 0 ; i--) {
int src_i = Collections.binarySearch(src, dest.get(i));
if(src_i >= 0)
// if element is found in src list, remove it from src list
src.remove(src_i);
else
// if element is NOT found in src list, remove it from dest list
dest.remove(i);
}
}
private static void copy(List dest, List src, Comparator c) {
// go through dest list to search if every element is in the new list
// travel backwards through dest because elements might be removed
for(int i = dest.size()-1; i >= 0 ; i--) {
int src_i = Collections.binarySearch(src, dest.get(i), c);
if(src_i >= 0)
// if element is found in src list, remove it from src list
src.remove(src_i);
else
// if element is NOT found in src list, remove it from dest list
dest.remove(i);
}
}
private static void addAll(List dest, List src, Verify v) {
// verify each element in src list before adding it to dest list
for(Object o: src)
if(v.verify(o))
dest.add(o);
}
}
答案 0 :(得分:6)
最简单的解决方案不是创建列表B的副本吗?这只需要创建一个底层数组的副本,这比复杂的算法需要更少的时间和精力(更不用说维护起来容易了)。
答案 1 :(得分:6)
我退后一步,考虑一下你的程序设计。听起来有一个管理所有玩家的课程更合理 - 保存它们,更新它们,分发对它们的引用。然后只需不在其他任何地方持有对Player的引用,保持对你的PlayerManager(或任何你想要调用它)的引用,并查询它以获得玩家。
这将为您提供一个规范列表,您无需担心过时的引用。
答案 2 :(得分:1)
但是,每当我在列表中搜索播放器时,我首先通过读取存储的文件来更新列表。
你为什么要这样做?搜索内存中的副本会更有意义。
哦,有一种非常简单的方法可以使a
包含与b
相同的内容:
a = b;
答案 3 :(得分:1)
我同意其他提交内容,这对您的应用程序来说似乎没有必要,但如果您想要一个能够在n ^ 2时间内完成所描述的算法的兴趣,那么就会有一个(并且它运行在n *中)记录时间)
sort list users (n log n)
sort list new_users (n log n)
iterate through users and new_users in parallel, adding or removing items from users as necessary ( n )
答案 4 :(得分:1)
您是否考虑过使用HashSet作为列表?这样你就可以addAll()
并拥有这些列表的联合。如果要保留原始订单,请使用LinkedHashSet。会快得多。您只需要在Player类中覆盖hashCode()
以返回其名称的哈希值。
答案 5 :(得分:1)
如果您使用集合而不是列表,那么您的程序会更快,即O(1)时间复杂度假设没有散列冲突。
for(User u : new_users) {
if (!users.contains(u)) {
users.add(u);
}
}
for(User u : users) {
if (!new_users.contains(u)) {
users.remove(u);
}
}