算法排序篇——选择排序与插入排序

个人算法学习笔记:算法基础之——SelectionSort,InsertionSortjava

  • 选择排序原理
  • 选择排序代码的实现
  • 插入排序原理
  • 插入排序的代码实现
  • 插入排序的优化

选择排序原理

选择排序动态演示
选择排序示例:
git

原数组

选择排序的思想是每次将未排序数组中的第一个元素与后面的元素依次比较,将最小的数字记录下来,并同未排序数组中的第一个元素交换位置。

1

2

3

后续过程再也不演示。

选择排序代码的实现

public class SelectionSort{
    // 排序算法中不会产生任何实例
    private SelectionSort(){}
    public static void sort(Comparable[]arr){
        for(int i=0;i<arr.length;i++){
            int minIndex = i;
            for(int j=i+1;j<arr.length;j++){
                if(arr[minIndex].compareTo(arr[j])>0){
                    minIndex = j;
                }
            }
            Comparable temp = arr[minIndex];
            arr[minIndex] = arr[i];
            arr[i] = temp;
        }
    }
}
复制代码

插入排序原理

插入排序动态演示
插入排序又叫扑克牌排序,我我的以为扑克牌排序(PorkerSort)要比InsertionSort这个名字更让人理解这个排序的过程。咱们在和别人打斗地主的时候,将一张牌又一张牌抓在手里的过程,这个过程实际上咱们就应用了插入排序这种思想。示例:
github

原数组

抓到了第一张牌:5,由于手里只有一张牌因此至关于已经排好了序。

I1

抓到了第二张牌:8,将手里全部的牌与抓到的牌进行比较放入合适的位置。

I2

后续过程再也不进行演示。

插入排序的代码实现

将插入排序的过程转换为Java代码:算法

public class InsertionSort{
    // 算法中不会产生任何实例
    private InsertionSort(){}
    public static void sort(Comparable[]arr){
        for(int i=1;i<arr.length;i++){
            for(int j=i;j>0;j--){
                if(arr[j].compareTo(arr[j-1])<0){
                    Comparable temp = arr[j];
                    arr[j] = arr[j-1];
                    arr[j-1] = temp;
                }else{
                    break;
                }
            }
        }
    }
}
复制代码

在代码中,第一个for循环for(int i=1;i<arr.length;i++),为何i的取值是从1开始的呢?其实也不难想到,在咱们抓到第一张牌的时候,这张牌已是“排好序”的一张牌了,在咱们从抓第二张牌开始,才会考虑到和手中的第一张牌做比较并排序的事情。另外本例的代码还能够在语法糖上进行简化:数组

public class InsertionSort{
    private InsertionSort(){}
    public static void sort(Comparable[]arr){
        for(int i=1;i<arr.length;i++){
            for(int j=i;i>0 && arr[j].compareTo(arr[j-1]);j--){
                Comparable temp = arr[j];
                arr[j] = arr[j-1];
                arr[j-1] = temp;
            }
        }
    }
}
复制代码

相比于选择排序,插入排序彷佛要好那么一些。选择排序是一个"纯正的"O(n^2)级别的算法,由于选择排序不管如何都会坚持本身的使命,执行完代码。而插入排序则不一样,当新插入的元素比较到某个位置时发现它没有这个位置的元素大,那么程序就会break出这层循环。能够形象地理解为:选择排序是“不撞南墙不回头”,插入排序则更像是“见好就收”。试想一下:若是一个数组为已经排好序的数组,可是咱们不知道它为一个已经排好序的数组,须要使用某个算法对其进行排序,若是咱们使用了选择排序,很显然选择排序依然会消耗O(n^2)的时间复杂度,而插入排序则不一样,插入排序会从一个O(n^2)级别的算法进化为一个O(n)级别的算法!如今对SelectionSort及InsertionSort进行测试。 测试代码:测试
bash

test
上述的测试结果是我10次测试结果中第10次的截图。测试内容为随机生成两个arr.length==10000且数据范围为0~9999闭区间的数组,在jdk1.8的测试环境下的测试数据。我共作了10组测试,10组测试中,SelectionSort的时间都要优于InsertionSort,咱们的分析是插入排序要优于选择排序,可是为何会形成这样的结果呢?

插入排序的优化

仔细分析插入排序与选择排序,其实不难发现,出现上述测试结果的主要缘由就在swap(交换)上。插入排序算法,每插入一个元素,当发现被插入的元素小于前面的元素时,咱们马上就让两者swap,若是继续比较,被插入的元素仍然小于前面的元素,还要再次进行swap。插入排序的优化思想就是让swap这个过程变为一个简单的赋值过程。如示例:
待插入的元素为:“5”,先将元素“5”存储起来。
学习

优化1

依次将带插入的元素与前面的元素进行比较。与swap不一样,这一次咱们使用赋值的思想。

优化2

将存储的带插入元素“5”,赋值到合适的位置。

优化3

代码以下:

public class InsertionSort{
    // 算法中不会产生任何实例
    private InsertionSort(){}
    public static void sort(Comparable[]arr){
        for(int i=1;i<arr.length;i++){
            Comparable temp = arr[i];
            int j;
            for(j=i;j>0;j--){
                if(temp.compareTo(arr[j-1]){
                    arr[j] = arr[j-1];
                }
            }
            arr[j] = temp;
        }
    }
}
复制代码

经测试,优化过的插入排序在时间上有了必定的压缩。虽然作了几回测试,优化的插入排序与选择排序在时间上不分上下,可是须要知道的是插入排序的意义就在于对几乎排好序的数据来讲,时间复杂度近乎为O(n),这个特性是选择排序所没有的。测试

相关文章
相关标签/搜索