什么是使一个列表等于另一个列表的有效算法?

时间:2009-12-07 03:46:57

标签: java algorithm search reference arraylist

假设我有一个列表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);
    }
}

6 个答案:

答案 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);
    }
}