树形选择排序有时也称为锦标赛排序。排序过程中,按照锦标赛比赛规则进行,将所有n个数据看成一棵完全二叉树的叶子结点,首先,完全二叉树的叶子结点两两比较,胜出的兄弟进入树的上一层继续和兄弟进行比较,如果某个叶子结点没有兄弟,则直接进入上一层,一直到二叉树的第二层的两个兄弟节点进行比较,胜出者为第一名。为了产生第二名,可将刚刚的到的第一名看成是最差的。再从此结点到根的路径上依次和相应的兄弟结点进行比较,最终得到树根,而得到第二民,依次下去,可得到第三名,第四名,......,最终得到最后的排名。
public static void main(String args[]){
int a[] ={1,9,5,6,11,2,7,32,3,15};
// simpleSelectSort(a);
List list = new ArrayList<>();
for(int i=0;i<a.length;i++){
list.add(a[i]);
}
// treeSelectGroup(list);
treeSelectSort(list);
}
/**
* 树形选择排序
* 算法思想:树形选择排序有时也称为锦标赛排序。排序过程中,按照锦标赛比赛规则进行,将所有n个数据看成一棵完全二叉树的叶子结点,
* 首先,完全二叉树的叶子结点两两比较,胜出的兄弟进入树的上一层继续和兄弟进行比较,如果某个叶子结点没有兄弟,则直接进入上一层,
* 一直到二叉树的第二层的两个兄弟节点进行比较,胜出者为第一名。为了产生第二名,可将刚刚的到的第一名看成是最差的。再从此结点到根
* 的路径上依次和相应的兄弟结点进行比较,最终得到树根,而得到第二民,依次下去,可得到第三名,第四名,......,最终得到最后的排名。
* @param a 排序的数组
*/
public static void treeSelectSort(List<Object> list){
System.out.println("开始树形选择排序:" + list.toString());
List<Object> treeList = createATree(list);//先生成一个树,每一层用ArrayList存着
int size = list.size() -1;//总共要进行将最大值替换成最小值的次数
System.out.println(treeList.toString());
for(int i=0;i<size;i++){
replaceTreeMax2Min(treeList);
}
}
/**
* 树形选择排序中生成一颗树
* @param list 要生成树的list
* @return List<Object> 生成后的树,存储每一层的数据
*/
public static List<Object> createATree(List<Object> list){
int n = (int) (Math.log(list.size())/Math.log(2));//先计算需要比较的次数
int sIndex = 0;//第一次开始遍历的位置
int eIndex = (int)Math.pow(2, n);//第一次结束遍历的位置,为2的n次方
List<Object> treeList = new ArrayList<>();//每遍历一层,都将数据存入当中
List<Object> nextList = new ArrayList<>();//下一层的数据
for(int i=0;i<=n;i++){
List<Object> nowList = new ArrayList<>();//当前层的数据
nowList.addAll(nextList) ;//当前层先取上一层比较后的数据
nextList.clear();//将上一层比较后的数据清零
if(i==0){//如果是第一层
nowList.addAll(list.subList(sIndex, eIndex));
}else if(i ==1){//如果是第二层
if(eIndex < list.size()){//如果第一层遍历的时候有数据没有进行遍历
n+=1;//要多遍历一层
nowList.addAll(list.subList(eIndex,list.size())); //将第一次没有遍历的数据加入到第二层当中遍历
}
}
treeList.add(nowList);//将当前层的数据加入treeList当中
for(int j=0;j<nowList.size();j+=2){//把数据两两分成一组进行对比
Object o1 = nowList.get(j);
if(j+1 >=nowList.size()){//判断数据是否越界,越界直接退出循环
nextList.add(o1);
break;
}
Object o2 = nowList.get(j+1);
if(Integer.parseInt(o1.toString()) > Integer.parseInt(o2.toString())){//判断哪个数据大,将数据大的加入下一层循环
nextList.add(o1);
}else{
nextList.add(o2);
}
}
}
return treeList;
}
/**
* 将一个树当中的最大值替换成最小值,继续比较,找到其中的最大值
* @param treeList 需要替换的树
*/
public static void replaceTreeMax2Min(List<Object> treeList){
int n = treeList.size();//总共的层数
List<Object> listLast = (List<Object>) treeList.get(n -1);//获取最后一层的list
Object oMax = listLast.get(0);//获取最大的一个数据
Object oMin = "0";//设置的最小值
Object oResult = oMin;//当前层比较的结果,默认值为0
for(int i=0;i<n;i++){//遍历每一层
List<Object> nowList = (List<Object>)treeList.get(i);//获取当前一层
for(int j=0;j<nowList.size();j++){//在当前层找到最大的值
if(nowList.get(j).equals(oMax)){//在当前行找到最大的值
nowList.set(j, oResult);//将最大值设置为上一层的比较结果
if(j%2 == 0){//如果当前的最大值位置为偶数,让其与右边一位比较
if(j+1 <nowList.size()){//判断数据是否越界,如果没有越界
oResult = (Integer.parseInt(nowList.get(j).toString())> Integer.parseInt(nowList.get(j+1).toString()))? nowList.get(j):nowList.get(j+1);//下一层的要替换的值为当前两者之间最大的一位
}else{//数组越界了
oResult = nowList.get(j);//下一层要替换的值为当前的值
}
}else{//如果当前位置为奇数,让其与左边一位比较
oResult = (Integer.parseInt(nowList.get(j).toString())> Integer.parseInt(nowList.get(j-1).toString()))? nowList.get(j):nowList.get(j-1);//下一层的要替换的值为当前两者之间最大的一位
}
}
}
}
System.out.println(treeList.toString());
}
下面看执行的结果: