算法二之树形选择排序

一、树形选择排序的基本思想

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

 

(2) 树形选择排序(Tree Selection Sort),这个过程可用一棵有n个叶子结点的 完全二叉树表示。
 

     例如,图表中的二叉树表示从8个数中选出最小数的过程。

8个叶子结点到根接点中的关键字,每个非终端结点中的数均等于其左右孩子结点中较小的数值,则根结点中的数即为叶子结点的最小数。在输出最小数之后,割据关系的可传递性,欲选出次小数,仅需将叶子结点中的最小数(13)改为“最大值”,然后从该叶子接点开始,和其左(或右)兄弟的数值进行比较,修改从叶子结点到根的路径上各结点的数,则根结点的数值即为最小值。同理,可依次选出从小到大的所有数。

(3) 由于含有n个子结点的完全二叉树的深度为 log2n+1,则在树形选择排序中,除了最小数值之外,每选择一个次小数仅需要进行 log2n次比较,因此,它的时间复杂度为 O(nlogn)。但是,这种排序方法尚 辅助存储空间较多、和“最大值”进行多余比较等缺点。为了弥补,威洛姆斯(J. willioms)在1964年提出了另一种形式的选择排序——堆排序。

 

 二、算法实现

算法从叶子节点中选出最大值,逆向存储在数据队列中,形成升序排序。

 public static void treeSelectionSort(int[] data) {
        //长度小于2,无需排序
        if(data.length<2){
            return;
        }
        
        int leafCount = 1;    //满二叉树的叶子节点数,非完全二叉树叶子节点数
        //计算出满二叉树的叶子节点数,节点数大于等于数据队列的长度
        while (leafCount < data.length) {
            leafCount *= 2;
        }

        int[] tree = new int[leafCount * 2];  //树,tree[0]不存储数据
        //data里面的值赋值到树叶子节点
        for (int i = 0; i < data.length; i++) {
            tree[tree.length - i - 1] = data[i];
        }
        //初始化还没有赋值的树叶子结点,赋值叶子节点最小值
        for (int i = data.length; i < leafCount; i++) {
            tree[tree.length - i - 1] = Integer.MIN_VALUE;
        }

        //初始化,构建整棵树
        for (int i = tree.length - 1; i > 1; i -= 2) {
            tree[i / 2] = Math.max(tree[i], tree[i - 1]);
        }
        data[data.length-1] = tree[1];   //将树根节点赋值于data
        
        int maxIndex;   //堆最大值所对应的叶子节点的下标
        //继续寻找剩下的最大值,逆向存储,升序排序
        for (int i = data.length-2; i >=0; i--) {
   
            maxIndex = tree.length - 1;  //默认堆最后一个位置
            //寻找树根值所在的叶子节点的位置
            while (tree[maxIndex] != tree[1]) {
                maxIndex--;
            }
            tree[maxIndex]=Integer.MIN_VALUE; //该叶子节点赋值最小值
            
            //调整树,根节点值最大
           while(maxIndex>1){
                //左叶子结点
                if (maxIndex % 2 == 0) {
                    tree[maxIndex / 2] = Math.max(tree[maxIndex] ,
                              tree[maxIndex + 1]);
                } else {
                    tree[maxIndex / 2] = Math.max(tree[maxIndex] ,
                              tree[maxIndex - 1]);
                }
                maxIndex/=2;//指向父节点
            }

            data[i] = tree[1];   //将树根节点赋值于data
        }
    }

 

转载于:https://www.cnblogs.com/maokun/p/7077816.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值