选择排序+插入排序算法动画演示

选择排序

先把最小的拿出来,剩下的,再把最小的拿出来

剩下的,再把最小的拿出来

每次选择还没处理的元素里的最小的元素

下面是动画演示过程

假设有一个数组,我们依次选择最小的数据出来

在这里插入图片描述

可否进行原地排序?

但是这里有一个问题,就是我们其实是开辟了两个存储空间,那么有没有可以优化的地步呢?

arr[i…n)未排序

arr[i…n)中的最小值

答案是有的,我们可以观看如下演示,利用i j两个指针

在这里插入图片描述

代码演示(使用带约束的泛型)

public class SelectionSort{
    private SelecttionSort(){}
    public static<E extends Comparable<E>> void sort(E[] arr)
    {
        //arr[0...i)是有序的,arr[i...n)是无序的
        for(int i = 0 ; i < arr.length;i++){
            //选择arr[i..n)中的最小值的索引
            int minIndex = i;
            for(int j=i;j<arr.length;j++){
               if(arr[j].compareTo(arr[minIndex])<0)
                   minIndex=j;
            }
            swap(arr,i,minIndex);
        }
    }
    private static<E> void swap(E[] arr,int i, int j)
    {
        E t=arr[i];
        arr[i]=arr[j];
        arr[j]=t;
    }
    public static void main(String[] args)
    {
        Integer[] arr={1,4,2,3,6,5};
        SelectionSort.sort(arr);
        for(int e:arr)
            System.out.print(e+" ");
        System.out.println();
        Student[] students = {new Student("Alice",98),
                              new Student("Bobo",100),
                              new Student("Charles",66)};
        SelectionSort.sort(students);
        for(Student student:students)
            System.out.print(student+" ");
        System.out.println();
        //两轮数据规模不一样
        int[] dataSiez={10000,100000};
        for(int n: dataSize){
             Integer[] arr = ArrayGenerator.generateRandomArray(n,n);
        	//验证排序结果
       		Sorting.sortTest("SelecitonSort",arr);
        }
       
    }
}




使用compareTo接口

自定义一个学生类

public class Student implements Comparable<Student>{
    private String name;//姓名
    private int score;//得分
    public Student(String name, int score){
        this.name = name;
        this.score = score;
    }
    @Override
    public boolean equals(Object student){
        if(this == student)return true;
        if(student==null) return false;
        if(this.getClass()!= student.getClass())return false;
        Student another = (Student)student;
        return this.name.equals(another.name);
    }
    @Override
    public int compareTo(Student another){
        if(this.score<another.score)
            return -1;
        else if(this.score == another.score)
            return 0;
        return 1;
        //简单写法,更加优雅的写法,这是分数从小到大的排序方法
        return this.score-anther.score;
    }
    @Override
    public String toString(){
        return String.format("Student(name: %s, score: %d)",name,score);
    }
}

选择排序法的复杂度分析

为了实现对于算法复杂度的分析,很明显,我们需要生成一个很大的数组来进行测试

public class ArrayGenerator{
    private ArrayGenerator(){}
    public static Integer[] generateOrderedArray(int n){
        Integer[] arr = new Integer[n];
        for(int i = 0 ; i < n ; i++)
            arr[i]=i;
        return arr;
        
        
    }
    //生成一个长度为n的随机数组,每个数字的范围是[0,bound)
    public static Integer[] generateRandomArray(int n,int bound){
        Integer[] arr = new Integer[n];
        Random rnd = new Random();
        for(int i  = 0; i < n ;i++)
            arr[i] = rnd.nextInt(bound);
        return arr
    }
}

辅助验证排序结果

public class SortingHelper{
    private SortingHelper(){}
    public static<E extends Comparable> boolean isSorted(E[] arr){
        for(int i = 1 ; i < arr.length; i++)
            if(arr[i-1].compareTo(arr[i]) > 0 )return false;
        return true;
    }
    //测试排序算法
    public static<E extends Comparable<E>> void sortTest(String sortname,E[] arr){
        //验证排序结果
        long startTime = System.nanoTime();
        if(sortname.equlas("SelectionSort"))
       		 SelectionSort.sort(arr);
        long endTime=System.nanoTime();
        double time = (endTime-startTime)/100000000.0;
        //检验算法正确性,如果不正确就要抛出异常
        if(!SortingHelper.isSorted(arr))
            throw new RuntimeException(sortname+" falied!");
        System.out.println(String.format("%s , n = %d : %f s"),sortname,arr.length.time);
    }
}

插入排序

image-20230308191155323

联想生活中的打牌知识,大多数人在拿到牌之后会采用插入的方式进行排列

在这里插入图片描述

每次处理一张牌,把这张牌插入到前面已经排好序的牌中

计算机逻辑实现整体动画演示

arr[0,i)已经排好序arr[i…n)没有排好序==(循环不变量)==,把arr[i]放到合适的位置
在这里插入图片描述

这里的插入和选择的区别到底是什么?

image-20230308192341096

选择是选择最小的元素,因此i之前都是最小的,就是数组排序完成之后应该存放的位置

但插入排序法不是这样的,每次只处理当前的元素,把当前的元素放在合适的位置。他不会动i还未遍历到的元素

代码实现

public class InsertionSort{
    private InsertionSort(){}
    public static<E extends Comparable<E>> void sort(E[] arr){
        for(int i = 0 ; i < arr.length; i++){
            //将arr[i]插入到合适的位置
            for(int j  = i ;j-1>=0;j--)
                if(arr[j].compareTo(arr[j-1])<0)
                    swap(arr,j,j-1);
            	else break;
        }
    }
}

插入排序法的小优化

每次交换其实是三次操作,先暂存一个元素,然后找到索引应该插入的位置,之后的元素我们可以进行平移优化操作

在这里插入图片描述

我们的操作用了赋值,只用了一次。

复杂度并未改变

public static<E extends Comparable<E>> void sort2(E[] arr){
        for(int i = 0 ; i < arr.length; i++){
            //将arr[i]插入到合适的位置
            E t = arr[i];
            int j;
            for(j=i;j-1>=0&&t.compareTo(arr[j-1])<0;j--){
                arr[j]=arr[j-1];
            }
            arr[j]=t;
        }
    }

插入排序的特性

极端情况

在这里插入图片描述

对于有序数组,插入排序的复杂度是o(n)

整体,插入排序的复杂度依然是o(n^2)

一个银行业务处理的数据,基本按照时间的顺序一个一个排序出来,只有个别业务排序时间较长。对于近乎有效的数据使用插入排序法是更好的选择,对于有效的数据时间复杂度O(n)

image-20230308203446103

选择排序不论是有序还是无序,时间复杂度都是一样的

而对于插入排序,有序的数据更快速

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值