今天在做游戏的联赛系统,假如有N 人报名参加联赛,服务器记录下报名人数,并对这些人的战斗后的结果进行排序,决出前16强或者8强。
网上找了下锦标赛排序算法,内容真少。总结下:
1:建树:这里说的建树是建立一颗完全二叉树。当参加排序的数组不足2的N次幂,将其补足。直到满足建立一个完全二叉树
2:当某结点的比较对手的参选标志为“不再参选”,该结点自动升入双亲结点,此动作不计入排序码比较次数。每次比较出来的第一名都标记为不参赛。
3:最终结果是返回到原来的数组之中
4:堆排序,资料很多,不多说。
/**
* 联赛系统分组
*
* @author Administrator
*/
public class Competition {
/**
* Player改为玩家ID存储
*/
private Player[] playerArray;
public Competition() {
int playerNum = World.getIns().getCompetition().size();
Player[] playerArray = (Player[]) World.getIns().getCompetition()
.toArray();
TournamentSort(playerArray,playerNum);
//比赛后结果排序按照数组顺序,放入playerArray中
}
/**
* 创建一颗树
* @param a
* @param n
*/
public static void TournamentSort(Player[] player, int n) {
TournamentPlayer[] tree;
int bottomRowSize = nearestPowerOfTwo(n);// 计算满足>=n的2的最小次幂的数:
int TreeSize = 2 * bottomRowSize - 1;
int loadindex = bottomRowSize - 1; // 外结点开始位置:从根节点开始往下数
tree = new TournamentPlayer[TreeSize];
for (int i = 0; i < TreeSize; i++) {
tree[i] = new TournamentPlayer();
}
int j = 0; // 在数组player中取数据指针
for (int i = loadindex; i < TreeSize; i++) { // 复制数组数据到树的外结点中
tree[i].setIndex(i); // 下标
if (j < n) {
tree[i].setActive(1);
tree[i].setData(player[j++]);
} // 复制数据
else {
tree[i].setActive(0); // 后面的结点为空的外结点
}
// System.out.println(tree[i].getIndex()+" "+ tree[i].getData());
}
int i = loadindex; // 进行初始比较寻找最小的项
while (i != 0) {
j = i;
while (j < 2 * i) { // 处理各对比赛者
Player playerRight = tree[j].getData();
Player playerLeft = tree[j + 1].getData();
// @ TODO 计算战斗,返回左边赢
boolean isLeftWin = true;
if (tree[j + 1].getActive() == 0 || isLeftWin == true)
tree[(j - 1) / 2] = tree[j]; // 胜者送入双亲
else
tree[(j - 1) / 2] = tree[j + 1];
// System.out.println(tree[(j - 1) / 2].getIndex()+" "+ tree[(j
// - 1) / 2].getData());
j += 2; // 下一对参加比较的项
}
i = (i - 1) / 2; // i退到双亲, 直到i=0为止
// System.out.println(tree[(j - 1) / 2].getIndex() + " "
// + tree[(j - 1) / 2].getData());
}
for (i = 0; i < n - 1; i++) { // 处理其它n-1元素
player[i] = tree[0].getData(); // 当前最小元素送数组a
System.out.println(player[i]);
tree[tree[0].getIndex()].setActive(0); // 该元素相应外结点不再比赛
UpdateTree(tree, tree[0].getIndex()); // 从该处向上修改
}
player[n - 1] = tree[0].getData();
System.out.println(player[n - 1]);
// return tree;
}
/**
* 每次比较出胜者之后,更新得到下一次比较的胜者
* i是表中当前最小元素的下标, 即胜者。从它开始向上调整。
* @param tree
* @param i
*/
public static void UpdateTree(TournamentPlayer[] tree, int i) {
if (i % 2 == 0)
tree[(i - 1) / 2] = tree[i - 1]; // i为偶数, 对手为左结点
else
tree[(i - 1) / 2] = tree[i + 1]; // i为奇数, 对手为右结点
// 最小元素输出之后, 它的对手上升到父结点位置
i = (i - 1) / 2;
int j = 0;// i上升到双亲结点位置
while (i != 0) {
if (i % 2 == 0)
j = i - 1; // 确定i的对手是左结点还是右结点
else
j = i + 1;
if (tree[i].getActive() == 0 || tree[j].getActive() == 0) {// 比赛对手中间有一个为空
if (tree[i].getActive() != 0)
tree[(i - 1) / 2] = tree[i];
else
tree[(i - 1) / 2] = tree[j];
}// 非空者上升到双亲结点
else // 比赛对手都不为空
{
Player playerRight = tree[i].getData();
Player playerLeft = tree[j].getData();
// @ TODO 计算战斗,返回左边赢
boolean isLeftWin = true;
if (isLeftWin)
tree[(i - 1) / 2] = tree[i];
else
tree[(i - 1) / 2] = tree[j]; // 胜者上升到双亲结点
i = (i - 1) / 2; // i上升到双亲结点
}
}
}
/**
* 得到最接近且大于
* number的2的N的方
* @param number
* @return
*/
public static int nearestPowerOfTwo(int number) {
--number;
number |= number >> 16;
number |= number >> 8;
number |= number >> 4;
number |= number >> 2;
number |= number >> 1;
++number;
return number;
}
public static void main(String[] args) {
Player[] relust = new Competition().getPlayerArray();
}
public Player[] getPlayerArray() {
return playerArray;
}
public void setPlayerArray(Player[] playerArray) {
this.playerArray = playerArray;
}
}