【问题标题】:Sorting - speed and performance分拣 - 速度和性能
【发布时间】:2018-08-09 12:14:38
【问题描述】:

我正在按排名顺序对我游戏中的玩家进行排序,因此,首先是管理员,然后是版主,一直到玩家。这是我的那部分代码:

/*
     * 2 -> Administrator, 1 -> Moderator, 6 -> Supporter, 14 -> Dicer, 8 -> Ultra
     * Donator, 13 -> Extreeme Donator, 9 -> Donator
     */

    Integer[] sortedRanksRights = { 2, 1, 6, 14, 8, 13, 9, 0 };
    ArrayList<Player> sortedPlayers = new ArrayList<Player>();

    // Loop over and add the sorted players to the list according to ranks
    for (int i = 0; i < sortedRanksRights.length; i++) {
        for (Player pp : World.getPlayers()) {
            if (pp.getRights() != sortedRanksRights[i])
                continue;
            else
                sortedPlayers.add(pp);
        }
    }

效果很好!! 但后来我有了一个想法,将管理员在他们之间分类为 所有者,共同所有者,然后是其他管理员。这是我的第二部分代码:

    if (sortedPlayers.size() > 1) {
        int place = 0;
        for (int i = 0; i < Settings.MAIN_ACESSS.length; i++) {
            if (World.getPlayerByDisplayName(Settings.MAIN_ACESSS[i]) != null) {
                if (!sortedPlayers.get(place).getUsername().toLowerCase()
                        .equals(Settings.MAIN_ACESSS[i].toLowerCase())) {
                    for (int j = 0; j < sortedPlayers.size(); j++) {
                        if (!sortedPlayers.get(place).getUsername().toLowerCase()
                                .equals(Settings.MAIN_ACESSS[i].toLowerCase())) {
                            Player target = sortedPlayers.get(place);
                            Player mine = sortedPlayers.get(j);
                            sortedPlayers.set(place, mine);
                            sortedPlayers.set(j, target);
                            place++;
                            break;
                        }
                    }
                } else {
                    place++;
                }
            }
        }
    }

main_access 具有所有者和共同所有者的名称。

这也有效,但我认为这不是实现这一目标的最佳方式。看着我什至写的代码让我很困惑啊哈哈。所以让我解释一下。

这会检查是否有超过 1 个玩家在玩游戏进行排序,然后运行一个循环到具有所有者的 main_access,然后是数组上的共同所有者名称,并检查他们是否在线。如果是这样,它会检查排序列表中的名字是否不是所有者。然后它运行一个循环来检查列表中的所有者在哪里并替换两个玩家,以便所有者在列表的顶部。我希望这不会令人困惑。

我的方法好吗?如果没有,有什么建议吗?游戏可能有数千名玩家在玩,所以速度和性能都被考虑在内。

【问题讨论】:

  • 为什么不用Collections来存储播放器,用Comparator接口定义排序更简单?
  • Collections.sort()Arrays.sort() 不适合您的Comparator 吗?这样您就可以将排序算法与比较逻辑(即如何确定顺序)分开。
  • 旁注:您可以使用xxx.equalsIgnoreCase(yyy) 代替xxx.toLowerCase().equals(yyy.toLowerCase()) - 更短且更具可读性
  • 其实我还不知道收藏。我对编程很陌生,没有遇到收藏。我会去研究他们,谢谢你的信息。另外,如果您能就我当前的问题给我一个示例代码,我将不胜感激并很高兴。谢谢!!
  • 你用 'i' 变量进行了两次比较是否正常:if (!sortedPlayers.get(place).getUsername().toLowerCase().equals(Settings.MAIN_ACESSS[i].toLowerCase())) {

标签: java performance sorting


【解决方案1】:

如果排序类别的括号是静态的并且永远不会改变。您可以使用bucket sort,这将为您提供 O(n)。

想法是将对象排列在各个桶中(在您的情况下为 2 级桶),并以固定的方式遍历桶。

例如:

输入:

player1: Moderator
player2: admin
player3: Donator
player4: Dicer

你需要遍历整理成这样的东西,

Admin: [player2]
Moderator: [player1]
Donator: [player3]
Dicer: [player4]

现在您只需要按固定顺序遍历这些存储桶并读出其中的玩家。

【讨论】:

    【解决方案2】:

    这里有一个关于如何根据排名和其他基于收藏等属性对玩家进行排序的建议。我会从你的代码中转移一些内容,但我希望你仍然能理解。

    首先,让我们定义枚举Rank

    enum Rank { 
      Administrator(1), 
      Moderator(2), 
      ...;
    
      //note that you could use the ordinal, i.e. position of the value as the priority 
      //but doing it that way allows you to use some other ordering if needed
      private final priority;
    
      Rank(int prio ) {
        priority = prio;
      }
    
      public int getPriority() {
        return prio;
      }
    }
    

    还有另一个枚举它们的状态(这里我们使用序数来演示):

    enum Status {
      OWNER,
      CO_OWNER,
      PLAYER
    }
    

    现在我们有了一个游戏的玩家列表(我使用列表是因为我们需要一个可排序的集合):

    List<Player> players = ...;
    

    然后我们对其进行排序:

    Collections.sort(players, new Comparator<Player>() {
      public int compare( Player left, Player right) {
        //first compare by rank priority
        int r = left.getRank().getPriority().compareTo(right.getRank().getPriority());
    
        //If ranks are equal, compare by status. 
        //If that should only happen for a certain rank, e.g. ADMINISTRATOR, 
        //then additionally check && left.getRank() == ADMINISTOR.
        //Assuming ranks have different priorities, if r is 0 that means both have the same rank
        if( r == 0 ) {
          r = left.getStatus().compareTo(right.getStatus());
        }
    
        //finally sort players by their name if rank and status are equal
        if( r == 0 ) {
          r = left.getUsername().compareToIgnoreCase(right.getUsername());
        }
    
        return r;
      }
    });
    

    使用 Java 8,比较器也可以这样构造(我现在无法编译,所以可能会出现错误):

    Comparator<Player> comp = Comparator.comparing( player -> player.getRank().getPriority() )
                                        .thenComparing( player -> player.getStatus() )
                                        .thenComparing( player -> player.getUsername().toLowercase() );
    

    【讨论】:

    • 谢谢,但我有这个未定义.. left.getRank() 和 left.getStatus() ??
    • @qistarlei.ba 这就是为什么我说我会从你的代码中转移一些东西。您可以在Player 中定义它,也可以根据实际情况调整您的代码。问题是我们没有关于 Player 的信息。
    【解决方案3】:

    我建议不要尝试使用自己的排序方法,而只需将 Player 设为 Comparable 并在您的玩家列表中调用 sort。另外,也许让你的等级类或枚举成员。

    public static class Player implements Comparable<Player> {
        public enum Rank {
            OWNER, CO_OWNER, ADMINISTRATOR, MODERATOR, SUPPORTER, DICER, ULTRA_DONOR, EXTREME_DONOR, DONATOR, NEWBIE
        }
    
        Rank rank; // init the players rank.
    
        @Override public int compareTo(Player o) {
            return rank.ordinal() - o.rank.ordinal();
        }
    
        // List<Player> players = ...;
        // Collections.sort(players);
    }
    

    如果您不想使用类或枚举并且仍想坚持使用整数,那么我建议按照您希望它们排序的顺序让整数代表排名(0 -&gt; Owner, 1 -&gt; Co Owner, 2 -&gt; Administrator),这样您仍然可以使用@ 987654325@.

    【讨论】:

    • 据我了解,OWNER 和 CO_OWNER 不是等级而是角色,即玩家可以是管理员所有者等。
    • 在这个方案中,所有者仍然可以被视为管理员,但高于普通的管理员。在游戏服务器的情况下,我假设所有者可以取消管理他们下方的某人,因此他们可能仍然应该是单独的等级。
    猜你喜欢
    • 2018-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-25
    • 1970-01-01
    相关资源
    最近更新 更多