选择排序之树形选择排序(七)

树形选择排序又称锦标赛排序(Tournament Sort),是一种按照锦标赛的思想进行选择排序的方法。首先对n个记录的关键字进行两两比较,然后在n/2个较小者之间再进行两两比较,如此重复,直至选出最小的记录为止。

package com.test.sort;


public class TreeSelectSort {

    /**
     * 选择排序之树形选择排序
     * @param args
     * 效率:时间复杂度O(nlogn),占用较多的辅助空间
     */
    public static void main(String[] args) {
        treeSelectSort();//树形选择排序
    }
    
    /**
     * 树形选择排序
     * 思路:
     * 1.将数组的元素两两相比较,得到n/2个较小的元素,
     * 2.重复步骤1,直至取到最小的元素。
     * 3.将剩余n-1个元素继续1,2中步骤比较
     * 注:此处用到完全二叉树的性质
     * 使用完全二叉树实现:将n个元素放到二叉树的最后n个位置,两两比较较小的放到二者父亲的位置,直至将最小值放到根节点为止;
     * 第一次取到最小值后,将该值取出放到原来数组的第一个位置,将二叉树中该值得为设置为最大值Integer.MAX_VALUE,进行
     * 下一轮比较。
     */
    public static void treeSelectSort() {
        int [] a = new int[]{12,123,23,1,32,45,32,34,0,23,348,1,2,323};
        int len = a.length;
        int treeSize = 2 * len - 1; // 完全二叉树的节点数
        int[] tree = new int[treeSize];
        int j = treeSize;
        //将数组放到tree中
        for (int i = len-1; i >= 0; i--) {
            tree[j-1] = a[i];
            j--;
        }
        // 根据叶子节点两两比较,去较小的,填充非叶子节点(即填入到父节点,根据完全二叉树特性可以确定父节点位置(i-1)/2)
        for (int i = treeSize-1; i > 0; i-=2) { 
            tree[(i-1)/2] = tree[i]>tree[i-1] ? tree[i-1] : tree[i];
        }
        
        
        //重复寻找最小值,将最小值按顺序重新放回原来的数组
        int ii = 0;
        while (ii < len) {
            int min = tree[0];//数组比较后的最小值
            int minIndex = 0;
            //确定最小值在tree中的位置
            for (int i = treeSize-1; i > 0; i--) {
                if(min==tree[i]){
                    minIndex = i;
                    // 将最小值设置为最大(设置为Integer.MAX_VALUE)
                    tree[i] = Integer.MAX_VALUE; //设置一个最大值标志
                    break;
                }
            }
            
          //将最小值按顺序重新放回原来的数组
            a[ii++] = min;
           
            // 找到其兄弟节点
            while (minIndex > 0) {//如果其还有父节点,继续向上寻找并比较,直至将最小值放到根节点
                if (minIndex % 2 == 0) {//如果为右节点,跟其左节点作比较,取最小值
                    tree[(minIndex-1)/2] = tree[minIndex]>tree[minIndex-1] ? tree[minIndex-1] : tree[minIndex];
                    minIndex = (minIndex - 1) / 2; //设置为父节点的索引,继续向上比对
                } else {//如果为左节点,跟其右节点作比较,取最小值
                    tree[minIndex/2] = tree[minIndex]>tree[minIndex+1] ? tree[minIndex+1] : tree[minIndex];
                    minIndex = minIndex / 2; //设置为父节点的索引,继续向上比对
                }
            }
        }
        
        for (int i = 0; i < a.length; i++) {
            if(i==a.length-1){
                System.out.print(a[i]);
            }else{
                System.out.print(a[i]+", ");
            }
        }
    }    
}
效率:时间复杂度O(nlogn)

转载于:https://www.cnblogs.com/quyanhui/p/10299242.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值