一. 關於“擂臺比武”
假設現在有一堆人要進行擂臺比武,他們的戰鬥力如下:
[5, 1, 6, 3, 4, 2, 8]
數字越小代表戰鬥力越強
現在採用抽籤模式,兩兩對決,勝者進入下一輪(如果奇數,單獨人員可直接晉級),情況如下:
那麼,如何把所有人的戰鬥力排名算出來呢?
二. 歸併算法
如同擂臺比武,先拆分成分各組,直到細分爲單個,開始比較後合併
注意點:
- 拆分的時候要注意奇偶數的問題
- 合併的時候要注意比較排序,當一個數組排序完成,另外一個要把剩餘的全部補充
三. 代碼示例
/**
* @author yanghao
* @version MergeTest.java, v 0.1 2020-03-02 15:10
*/
public class MergeTest {
public static void main(String[] args){
Integer[] data = {5, 1, 6, 3, 4, 2, 8};
data = sort(data);
for(int i = 0;i < data.length; i ++){
System.out.print(data[i] + " = ");
}
}
private static Integer[] sort(Integer[] data){
int length = data.length;
if(length == 0){
return new Integer[0];
}
//分割
int mid = length%2 == 1 ? (length - 1)/2 : length/2 - 1;
Integer[] dataLeft = split(data, 0, mid);
Integer[] dataRight = split(data, mid + 1, length - 1);
//判斷是否要繼續分割
if(dataLeft.length > 1){
dataLeft = sort(dataLeft);
}
if(dataRight.length > 1){
dataRight = sort(dataRight);
}
//排序後合併
return merge(dataLeft, dataRight);
}
/**
* 拆分數組
* @param data
* @param start
* @param end
* @return
*/
private static Integer[] split(Integer[] data, int start, int end) {
Integer[] temp = new Integer[end - start + 1];
for(int i = 0;i <= end - start; i ++){
temp[i] = data[start + i];
}
return temp;
}
/**
* 合併數組
* @param dataLeft
* @param dataRight
* @return
*/
private static Integer[] merge(Integer[] dataLeft, Integer[] dataRight) {
Integer[] data = new Integer[dataLeft.length + dataRight.length];
int i = 0,j = 0,k = 0;
while (i < dataLeft.length && j < dataRight.length){
if(dataLeft[i] <= dataRight[j]){
data[k] = dataLeft[i];
i ++;
}else{
data[k] = dataRight[j];
j ++;
}
k ++;
}
//如果左邊數組沒有取完
while (i < dataLeft.length){
data[k] = dataLeft[i];
i ++;
k ++;
}
//如果右邊數組沒有取完
while (j < dataRight.length){
data[k] = dataRight[j];
j ++;
k ++;
}
return data;
}
}