更新ArrayList的最高性能方法

时间:2013-10-15 21:41:17

标签: java performance arraylist

我有一个ArrayList,每秒更新一次,进行一些基本检查,并维护当前满足一系列条件的玩家列表。

我想知道执行此操作的最佳方式是我有2个提议的解决方案。

public void update() {
    for (Player player : Bukkit.getOnlinePlayers()) {
        if (!playersOnLadder.contains(player)) {
            if (checkPlayerOnLadder(player)) {
                playersOnLadder.add(player);
            }
        } else {
            if (checkPlayerOnLadder(player)) {
                playersOnLadder.remove(player);
            }
        }
    }
}

public void update() {
            playersOnLadder.clear();

    for (Player player : Bukkit.getOnlinePlayers()) {
        if (checkPlayerOnLadder(player)) {
            playersOnLadder.add(player);
        }
    }
}

在任何给定时间,此阵列列表中通常会有大约75名玩家。 “在梯子方法上检查玩家看起来像这样:

private boolean checkPlayerOnLadder(Player player) {
    int ladderAbsolute = this.getX()+this.getZ();
    int playerAbsolute = (int) player.getLocation().getX()+ (int) player.getLocation().getZ();

    //If the player is within 4 blocks (2 in each direction) of the ladder then return true.
    if (ladderAbsolute == playerAbsolute || (ladderAbsolute-2 > playerAbsolute && ladderAbsolute+2 < playerAbsolute)) {
        return true;
    } else {
        return false;
    }
}

EDITED已转换为HashSet

4 个答案:

答案 0 :(得分:3)

如果仅限于这两个选项,那么我会使用选项编号2作为性能更高的解决方案。

在选项1中,remove中的ArrayList操作为O(n),因为它必须找到玩家O(n)并在找到后移除玩家,将所有人向下移动在O(n)。以这种方式循环整个玩家列表是O(n ^ 2)。

选项2只需清除以O(n)开头的列表。 add操作是O(1)(除非需要调整大小),因此将它们全部添加也是O(n)。选项2总体为O(n)。

ArrayList替换为HashSet(并在hashCode上实施equalsPlayer)可能是一种选择。散列操作是O(1),因此遍历所有玩家并执行这些操作也是O(n)。如果您需要稍后快速找到特定Player,请使用HashSet,因为containsHashSet中为O(1),但在ArrayList中为O(n) {{1}}。

答案 1 :(得分:1)

请使用字典类型的数据结构进行此类记账。 HashSet(确保正确实现hashCode!)很可能是你想要的。语义和性能明智。

但是,我不明白你的阶梯和附带的算法。

答案 2 :(得分:1)

最好的方法可能是使用HashSetPlayer doesn't override hashCode,所以HashMap<int, Player>可以使用播放器的entityId

这样的事情:

HashMap<int, Player> playersOnLadder; /* make sure to initialize this */

public void update() {
    for (Player player : Bukkit.getOnlinePlayers()) {
        if (checkPlayerOnLadder(player)) {
            playersOnLadder.put(player.getEntityId(), player);
        } else {
            playersOnLadder.remove(player.getEntityId());
        }
    }
}

因为它是HashMapput多次没问题,如果给定的obejct不在地图中,HashMap.remove可以安全地调用(它将返回{{1}但是,在这种情况下没有必要检查它。)


更好的是将代码更改为使用events。看起来PlayerJoinEventPlayerQuitEvent可能对您有用,无论您的null函数是什么,都可以在响应事件时完成。

答案 3 :(得分:0)

“75名玩家”+“每秒一次”=&gt;继续前进!

你可以每秒获得几纳秒的时间,这可能会使你的代码快一点0.0000001%......

现在更快的选择可能是这个(分配通常比清算便宜):

public void update() {
    // pre sizing the list saves unnecessary resizing operations.
    playersOnLadder = new ArrayList<>(Bukkit.getOnlinePlayers());
    for (Player player : Bukkit.getOnlinePlayers()) {
        if (checkPlayerOnLadder(player)) {
            playersOnLadder.add(player);
        }
    } 
}