• 数据结构与算法系列——排序(6)_树形选择排序


    1. 工作原理(定义)

      树形选择排序Tree Selection Sort),又称锦标赛排序Tournament Sort),是一种按照锦标赛思想进行选择排序的方法。

      首先对n个记录的关键字进行两两比较,然后在其中[n/2](向上取整)个较小者之间再进行两两比较,如此重复,直至选出最小关键字的记录为止。

      胜者树和败者树是完全二叉树,是树形选择排序的变形。

    2. 算法步骤 

     这个过程可以用一棵有n个叶子结点的完全二叉树表示。如图中的二叉树表示从8个关键字中选出最小关键字的过程:

      

      8个叶子结点中依次存放排序之前的8个关键字,每个非终端结点中的关键字均等于其左、右孩子结点中较小的那个关键字,则根结点中的关键字为叶子结点中的最小关键字

      在输出最小关键字之后,根据关系的可传递性,欲选出次小关键字,仅需将叶子结点中的最小关键字(13)改为“最大值”,然后从该叶子结点开始,和其左右兄弟的关键字进行比较,修改从叶子结点到根结点的路径上各结点的关键字,则根结点的关键字即为次小值

      同理,可依次选出从小到大的所有关键字。

    3. 图示

    为了减少简单选择排序,我们利用前n-1次比较信息,减少下次选择。类似于锦标赛。根据锦标赛传递关系。亚军只能从被冠军击败的人中选出。 

    实际算法中,我们把需要比较的记录全部作为叶子,然后从叶子开始两两比较,从底向上最后形成一棵完全二叉树。在我们选择出最小关键字后,根据关系的传递,只需要将最小关键字的叶子节点改成无穷大,重新从底到上比较一次就能够得出次小关键字。 


    然而虽然树形选择比较能够减少比较次数,却增加了辅助空间的使用。为了弥补此缺憾,威廉姆斯于1964年提出了堆排序。

      具体的例子:

    对 n 个关键字两两比较,直到选出最小关键字为止,一趟排序结束

            

    反复这个过程,仅需将叶子结点的最小关键字改为最大值∞,即可

    然后从该叶子结点开始,继续和其左右兄弟的关键字比较,找出最值

    4. 性能分析

    1. 时间复杂度

    时间复杂度:由于含有 n 个叶子结点的完全二叉树的深度为,则在树形选择排序中,除了最小关键字外,每选择一个次小关键字仅需进行   次比较,故时间复杂度为 O(n logn)。

    缺点:  1、与“∞”的比较多余;  2、辅助空间使用多。

    为了弥补这些缺点,1964年,堆排序诞生。

    2. 空间复杂度

      选择排序过程中,需要临时变量存储待排序元素,因此空间复杂度为O(n)。

    3. 算法稳定性 

      选择排序是不稳定的算法,在选择数值和交换过程中它们的顺序可能会发生变化。

    6. 具体代码

    import java.util.Arrays;
    
    public class TreeSelectionSort{
        public static void main(String[] args) {
            int[] arr = {8,7,6,5,4,3,2,1};
            System.out.println(Arrays.toString(treeSelectionSort(arr)));
        }
    
        public static int[] treeSelectionSort(int[] mData) {
            int n = mData.length;
            int MinValue = Integer.MIN_VALUE;
            // 得到树上节点的个数
            int baseSize = 1;
            while (baseSize < n) {
                baseSize *= 2;
            }
            int treeSize = baseSize * 2 - 1;// 树的大小
            // 初始化树,从下标1-treeSize,忽略下标0
            int[] tree = new int[treeSize+1]; 
            int i = 0;
            for (; i < n; i++) {
                tree[treeSize - i] = mData[i];
            }
            for (; i < baseSize; i++) {
                tree[treeSize - i] = MinValue;
            }
            // 构造一棵树
            for (i = treeSize; i > 1; i -= 2) {
                tree[i / 2] = (tree[i] > tree[i - 1] ? tree[i] : tree[i - 1]);
            }
            
            //每一趟得到一个最大值
            while (n > 0 ) {
                // 根节点是最大值
                int max = tree[1]; 
                // 倒着放入数组之后得到的正向数组就是 从小到大
                mData[--n] = max;  
                // 将叶子节点中最大值的位置赋值为最小值
                int maxIndex = treeSize;
                while (tree[maxIndex] != max) {
                    maxIndex--;
                }
                tree[maxIndex] = MinValue;
                // 重新调整胜者树的值
                while (maxIndex > 1) {
                    if (maxIndex % 2 == 0) {
                        tree[maxIndex / 2] = (tree[maxIndex] > tree[maxIndex + 1] ? tree[maxIndex] : tree[maxIndex + 1]);
                    } else {
                        tree[maxIndex / 2] = (tree[maxIndex] > tree[maxIndex - 1] ? tree[maxIndex] : tree[maxIndex - 1]);
                    }
                    maxIndex /= 2;
                }
            }
            return mData;
        }
    }

    7. 参考网址

    1. 简单选择排序 Selection Sort 和树形选择排序 Tree Selection Sort
    2. 常见的五类排序算法图解和实现(选择类:简单选择排序,锦标赛排序,树形选择排序,堆排序)
    3. 选择排序之树形选择排序(TreeSelectionSort)
    4. https://baike.baidu.com/item/%E6%A0%91%E5%BD%A2%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F/5720280?fr=aladdin
  • 相关阅读:
    mysql中删除重复记录,并保留重复数据中的一条数据的SQL语句
    架构设计文档提纲简描
    各大互联网公司架构演进之路汇总
    大数据安全规范
    生活启示
    mysql数据库分库分表(Sharding)
    大数据风控指标----查准率与查全率
    YARN和MapReduce的内存设置参考
    不要在linux上启用net.ipv4.tcp_tw_recycle参数
    [Spark经验一]Spark RDD计算使用的函数里尽量不要使用全局变量
  • 原文地址:https://www.cnblogs.com/haimishasha/p/10896825.html
Copyright © 2020-2023  润新知