Skip to content

Latest commit

 

History

History
174 lines (131 loc) · 7.21 KB

03.选择排序.md

File metadata and controls

174 lines (131 loc) · 7.21 KB

选择排序

  • 1.基本思想
  • 2.排序过程
  • 3.代码实现
  • 4.如何优化
  • 5.复杂度
  • 6.使用场景

好消息

  • 博客笔记大汇总【15年10月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计N篇[近100万字,陆续搬到网上],转载请注明出处,谢谢!所有博客陆续更新到GitHub上!
  • 链接地址:https://github.com/yangchong211/YCBlogs
  • 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!

0.选择排序种类

  • 选择排序分为三种,直接选择排序、树形选择排序(锦标赛排序)、堆排序(大根堆、小根堆)。
  • 直接选择排序和堆排序是不稳定排序,树形选择排序是稳定排序。

1.直接选择排序

1.1 基本思想

  • 在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;
  • 第二次遍历n-2个数,找到最小的数值与第二个元素交换;
  • 依此类推……
  • 第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成。

1.2 排序过程

  • 通过设置哨位,将哨位位置的数与哨位之后(包括哨位)的序列中最小的数进行交换,然后哨位递增,直到哨位到达数组中最后一个数为止。
  • image

1.3 代码实现

  • 如下所示
    /*
     * 直接选择排序
     */
    public static void selectSort1(int[] data) {
        int pos ;
        for (int i = 0; i < data.length; i++) {
            pos = i;
            // 找出从i开始,到数组末尾这段数组中最小的数,pos标志的是这个最小的数在数组中的位置
            for (int j = i + 1; j < data.length; j++) {
                if (data[j] < data[pos]) {
                    pos = j;
                }
            }
            // 交换两个数的位置
            if(pos != i){
                int temp = data[i];
                data[i] = data[pos];
                data[pos] = temp;
            }
        }
        for(int i=0;i<data.length;i++){
            System.out.println("yc1-----" +data[i]);
        }
    }
    

1.4 如何优化

  • 直接选择排序的最好时间复杂度和最差时间复杂度都是O(n²),因为即使数组一开始就是正序的,也需要将两重循环进行完,平均时间复杂度也是O(n²)。
  • 空间复杂度为O(1),因为不占用多余的空间。直接选择排序是一种原地排序(In-place sort)并且稳定(stable sort)的排序算法,优点是实现简单,占用空间小,缺点是效率低,时间复杂度高,对于大规模的数据耗时长。

1.5复杂度

  • 最好时间复杂度和最差时间复杂度都是O(n²)

2.树形选择排序(锦标赛排序)

2.1 基本思想

  • 树形选择排序利用满二叉树的性质,将待排序的数放入叶子节点中,然后同属于一个根节点的两个叶子节点相互比较,较小的叶子节点复制到其根节点,然后根节点之间再相互比较,直到整棵树的根节点,此时整棵树的根节点为待排序数组中最小的一个数,在下一次循环中要将这个数置为最大值,然后再开始循环,直到全部的数都被取出,排序完成。因为这种排序类似于比赛中的淘汰赛,所以又称之为锦标赛排序。

2.2 排序过程

  • 构造一棵满二叉树,要求可以将待排序数组全部放入叶子节点中
  • 将两个叶子节点中较小的数挪入根节点中,全部挪完之后,再将两个根节点中较小的数挪入它们的根节点中,直到整棵树的根节点。
  • 取出根节点中的数,将叶子节点中的这个数置为max,重复第二步,直到每个数都被取出过一次。

2.3 代码实现

  • 代码如下所示
    public static void treeSelectSort(int[] a){
        int len = a.length;
        int treeSize = 2 * len - 1;  //完全二叉树的节点数
        int low = 0;
        int[] tree = new int[treeSize];    //临时的树存储空间
        //由后向前填充此树,索引从0开始
        for(int i = len-1,j=0 ;i >= 0; --i,j++){      //填充叶子节点
            tree[treeSize-1-j] = a[i];
        }
    
        for(int i = treeSize-1;i>0;i-=2){ //填充非终端节点
            //noinspection unchecked
            tree[(i-1)/2] = ((Comparable)tree[i-1]).compareTo(tree[i]) < 0 ? tree[i-1]:tree[i];
        }
    
        //不断移走最小节点
        int minIndex;
        while(low < len){
            int min = tree[0];    //最小值
            a[low++] = min;
            minIndex = treeSize-1;
            //找到最小值的索引
            //noinspection unchecked
            while(((Comparable)tree[minIndex]).compareTo(min)!=0){
                minIndex--;
            }
            tree[minIndex] = Integer.MAX_VALUE;  //设置一个最大值标志
            //找到其兄弟节点
            while(minIndex > 0){      //如果其还有父节点
                if(minIndex % 2 == 0){   //如果是右节点
                    //noinspection unchecked
                    tree[(minIndex-1)/2] = ((Comparable)tree[minIndex-1]).compareTo(tree[minIndex])
                            < 0 ? tree[minIndex-1]:tree[minIndex];
                    minIndex = (minIndex-1)/2;
                }else{                   //如果是左节点
                    //noinspection unchecked
                    tree[minIndex/2] = ((Comparable)tree[minIndex]).compareTo(tree[minIndex+1])
                            < 0 ? tree[minIndex]:tree[minIndex+1];
                    minIndex = minIndex/2;
                }
            }
        }
    
    
        for(int i=0;i<a.length;i++){
            System.out.println("yc1-----" +a[i]);
        }
    }
    

其他内容

01.关于博客汇总链接

02.关于我的博客