八大排序算法


八大排序算法

1, 算法的基本概念

程序=数据结构+算法
算法中先学习排序算法
排序也成为排序算法(sort algorithm), 是将一组数据按照指定的顺序进行排列的过程

2, 八大排序算法基础

2.1, 排序算法分类

内部排序和外部排序

  • 内部排序:将所有的需要处理的数据都加载到内存中进行排序处理
  • 外部排序:数据量大或者其他原因, 无法把数据全部加载到内存中, 需要借助外部存储进行排序

image-20210424120743010

image-20210424120802030

image-20210424120820651

2.2, 时间复杂度

  • 时间复杂度其实是渐进时间复杂度的简称,是指计算时间的一个趋势的复杂度
T(n)=+7n+6T(n)=3+2n+2 : 时间复杂度都是:O()。
  
用常数1代替运行时间中的所有加法常数  T(n)=+7n+6  => T(n)=+7n+1
修改后的运行次数函数中,只保留最高阶项  T(n)=+7n+1 => T(n) = n²
去除最高阶项的系数 T(n) ==> T(n) ==> O()
  1. 常数阶O(1)

    int i=0;
    int j = 1;
    i++;
    j++;
    int m = i+j;
    
  2. 对数阶O(log2n)

    说明:在while循环里面,每次都将 i 乘以 2,乘完之后,i 距离 n 就越来越近了。假设循环x次之后,i 就大于 2 了,此时这个循环就退出了,也就是说 2 的 x 次方等于 n,那么 x = log2n也就是说当循环 log2n 次以后,这个代码就结束了。因此这个代码的时间复杂度为:O(log2n) 。 O(log2n) 的这个2 时间上是根据代码变化的,i = i * 3 ,则是 O(log3n) .

    int i=1;
    while(i<n) {
      i = i*2;
    }
    
  3. 线性阶O(n)

    说明:这段代码,for循环里面的代码会执行n遍,因此它消耗的时间是随着n的变化而变化的,因此这类代码都可以用O(n)来表示它的时间复杂度

    for(int i=0;i<n;i++){
      j = i;
      j++;
    }
    
  4. 线性对数阶O(nlog2n)

    说明:线性对数阶O(nlogN) 其实非常容易理解,将时间复杂度为O(logn)的代码循环N遍的话,那么它的时间复杂度就是 n * O(logN),也就是了O(nlogN)

    for(m=1;m<n;m++) {
      i=1;
      while(i<n) {
        i=i*2;
      }
    }
    
  5. 平方阶O(n2)

    说明:平方阶O(n²) 就更容易理解了,如果把 O(n) 的代码再嵌套循环一遍,它的时间复杂度就是 O(n²),这段代码其实就是嵌套了2层n循环,它的时间复杂度就是 O(nn),即 O(n²) 如果将其中一层循环的n改成m,那它的时间复杂度就变成了 O(mn)

    for(int i=0;i<n;i++) {
      for (int j=0;j<n;j++){
        ****
      }
    }
    
  6. 立方阶O(n3)

for(int i=0;i<n;i++) {
  for (int j=0;j<n;j++){
    for (int m=0;m<n;m++){
    	****
  	}
  }
}
  1. k次方阶O(nk) : 这里k>3
  2. 指数阶O(2n)

image-20210424121436088

说明:
常见的算法时间复杂度由小到大依次为:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)< Ο(nk) <Ο(2n) ,随着问题规模n的不断增大,上述时间复杂度不断增大,算法的执行效率越低
从图中可见,我们应该尽可能避免使用指数阶的算法

2.3, 平均时间复杂度和最坏时间复杂度

平均时间复杂度是指所有可能的输入实例均以等概率出现的情况下,该算法的运行时间。
最坏情况下的时间复杂度称最坏时间复杂度。一般讨论的时间复杂度均是最坏情况下的时间复杂度。 这样做的原因是:最坏情况下的时间复杂度是算法在任何输入实例上运行时间的界限,这就保证了算法的运行时间不会比最坏情况更长。
平均时间复杂度和最坏时间复杂度是否一致,和算法有关(如图:)。

image-20210424121523285

2.4, 八大排序算法

1, 冒泡算法

相邻的两个进行比较,如果前者比后者大,那么就把大的移动到后面。

第一轮把最大的移动到最后一位

第二位把次大的移动到倒数第二位

依次进行,直到有序(n个数最大进行n-1轮即可有序)

a06_01_Bubble_basic
package im.bool.a06_sort_algrithm;

/**
 * #Author : ivanl001
 * #Date   : 2020/2/24 9:53 AM
 * #Desc   : 排序算法之冒泡推算过程:
 *          这个过程中有一个优化过程:如果经过一轮冒泡,顺序完全没有变动,那么后续就不需要进行了,因为这个时候顺序已经排好了
 **/
public class a06_01_Bubble_basic {
    public static void main(String[] args) {

        int[] nums = {3, 9, -1, -2, 10};

        int temp;

        System.out.println("第一次冒泡:");
        for (int i=0;i<nums.length-1;i++) {
            if (nums[i] > nums[i+1]) {
                temp = nums[i];
                nums[i] = nums[i + 1];
                nums[i+1] = temp;
            }
        }
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i] + ", ");
        }
        System.out.println();


        System.out.println("第二次冒泡:");
        for (int i=0;i<nums.length-1-1;i++) {
            if (nums[i] > nums[i+1]) {
                temp = nums[i];
                nums[i] = nums[i + 1];
                nums[i+1] = temp;
            }
        }
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i] + ", ");
        }
        System.out.println();


        System.out.println("第三次冒泡:");
        for (int i=0;i<nums.length-1-2;i++) {
            if (nums[i] > nums[i+1]) {
                temp = nums[i];
                nums[i] = nums[i + 1];
                nums[i+1] = temp;
            }
        }
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i] + ", ");
        }
        System.out.println();


        System.out.println("第四次冒泡");
        for (int i=0;i<nums.length-1-3;i++) {
            if (nums[i] > nums[i+1]) {
                temp = nums[i];
                nums[i] = nums[i + 1];
                nums[i+1] = temp;
            }
        }
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i] + ", ");
        }
        System.out.println();
    }
}
a06_02_Bubble
package im.bool.a06_sort_algrithm;

import jdk.internal.org.objectweb.asm.tree.FrameNode;

import java.util.Arrays;

/**
 * #Author : ivanl001
 * #Date   : 2020/2/24 5:58 PM
 * #Desc   : 冒泡排序算法:两次循环实现
 **/
public class a06_02_Bubble {

    public static void main(String[] args) {

        /*int[] nums = {9, -2, -1, 3, 10, 100, -3, 3, 4, 20};
        bubbleSort(nums);
        for (int j = 0; j < nums.length; j++) {
            System.out.print(nums[j] + ", ");
        }
        System.out.println();*/


        int[] nums = new int[80000];
        for (int i = 0; i < 80000; i++) {
            nums[i] = (int) (Math.random() * 80000);
        }

//        System.out.println(Arrays.toString(nums));

        long startTime = System.currentTimeMillis();
        bubbleSort(nums);
        long endTime = System.currentTimeMillis();
        //9s左右
        System.out.println(endTime-startTime);
    }


    public static void  bubbleSort(int[] nums) {
        int temp;
        boolean isOrdered = false;

        //因为冒泡排序算法是两层循环,所以冒泡排序算法的时间复杂度是O(n^2)
        for (int i = 0; i < nums.length-1; i++) {
            isOrdered = true;
//            System.out.println("第" + (i+1) + "次冒泡:");
            //-------------------冒泡算法的精华代码--------------------
            for (int j = 0; j < nums.length - 1 - i; j++) {
                if (nums[j] > nums[j + 1]) {
                    temp = nums[j];
                    nums[j] = nums[j + 1];
                    nums[j + 1] = temp;
                    isOrdered = false;
                }
            }

            /*for (int j = 0; j < nums.length; j++) {
                System.out.print(nums[j] + ", ");
            }
            System.out.println();*/
            //这个地方是一个小优化。如果经过一轮,数据顺序完全没有变动
            if (isOrdered) {
                System.out.println("第" + (i+1) + "次循环");
                System.out.println("已经有序。。。");
                break;
            }
        }
    }
}
a06_03
  • 如果是向左冒泡,那么左边的边界需要依次变大
  • 如果是向右冒泡, 那么右边的边界需要依次变小
// 如果是向左冒泡,那么左边的边界需要依次变大
public static void bubbleSort(int[] arr) {
    for (int i = 0; i < arr.length; i++) {
        for (int j = arr.length-1; j > i; j--) {
            if (arr[j] < arr[j - 1]) {
                int temp = arr[j];
                arr[j] = arr[j - 1];
                arr[j - 1] = temp;
            }
        }
    }
}

// 如果是向右冒泡, 那么右边的边界需要依次变小
public static void bubbleSort_v1(int[] arr){
    for (int i = 0; i < arr.length; i++) {
        // 注意:这里j < arr.length-i-1, 是减去i哈
        for (int j = 0; j < arr.length-i-1; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j + 1] = temp;
            }
        }
    }
}

2, 快速排序(平分移动+迭代排序)-冒泡算法的优化

快速排序思路

首先以中间一个数字为基准,把该数右侧大于该数的移至该数左侧,把该数左侧大于数的移至该数右侧。这样大于该数的数字都在右侧,小于该数的都在该数左侧。

接着再使用迭代算法, 依次对左侧的进行相同方法的移动。

接着再使用迭代算法, 依次对右侧的进行相同方法的移动。

当迭代结束,该数组数字即是有序

a06_09_Quick
package im.bool.a06_sort_algrithm;

import java.util.Arrays;

/**
 * #Author : ivanl001
 * #Date   : 2020/2/27 7:22 PM
 * #Desc   : 快速排序法,这个是冒泡排序算法的优化。和冒泡算法属于同一排序算法
 *           快排的话, 在n值比较大的时候就比shell要好很多。
 *           如果都在8万数据的话, shell大概21ms,快排大概67ms
 *           如果是8000万数据, shell大概41s,快排只需要12s
 **/
public class a06_09_Quick {
    public static void main(String[] args) {
        /*int[] nums = {-9, 78, 0, 23, -567, 70};

        quickSort(nums, 0, nums.length - 1);
        System.out.println(Arrays.toString(nums));*/

        int[] nums = new int[80000];
        for (int i = 0; i < 80000; i++) {
            nums[i] = (int) (Math.random() * 80000);
        }

        long startTime = System.currentTimeMillis();
        quickSort(nums, 0, nums.length-1);
        long endTime = System.currentTimeMillis();
        //这里用了21ms左右, shell排序如果用前面的交换,大概5s, 插入排序1s左右, 冒泡大概9s,选择大概2s
        //所以移位法速度提升简直是非常非常大的
        System.out.println(endTime-startTime);
        //System.out.println(Arrays.toString(nums));

    }

    public static void quickSort(int[] arr, int left, int right) {
        int l = left;
        int r = right;

      	// 中间值
        int pivot = arr[(left + right) / 2];

        int temp = 0;

        while (l < r) {
         	  // 这里在中轴左边左边从头开始找,直到找到比中轴大或相等的值
            // 最后会找到中轴或者中轴右一位
            while (arr[l] < pivot) {
                l += 1;
            }
            // 这里在中轴右侧从尾部往前找, 直到找到比中轴小或相等的值
            // 最后会找到中轴或者中轴左一位
            while (arr[r] > pivot) {
                r -= 1;
            }

            // 当r<l的时候, 说明已经把两边的值已经挪动完成。
            // 相等的时候也可以跳出
            if (l >= r) {
                break;
            }

            // 交换
            temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp;

            // 这两步必不可少。因为如果当前的值和中轴值一样,那么这个地方要跳过,要不然就是死循环,因为交换后,值不变,然后继续交换,继续相等

            if (arr[l] == pivot) {
                r--;
            }
            if (arr[r] == pivot) {
                l++;
            }
        }

      	// 这个地方如果不添加,会死循环,因为跳不出来
        if (l == r) {
            l += 1;
            r -= 1;
        }

        // 走完前面的说明比中间值小或相等的都会挪到左边, 比中间值大或相等的都会挪到右边.
        if (left < r) {
            quickSort(arr, left, r);
        }

        if (right > l) {
            quickSort(arr, l, right);
        }
    }
}

3, 选择排序

大体思路:

第一轮从数组中选取最小的数据,放在第一位。

第二轮从第一个之后的那些数中选择最小的,放在第二位

第三轮从第二个之后的那些数中选取最小的,放在第三位

直至放到倒数第二位为止。

n个数字经过(n-1)轮后,即可保证有序

a06_03_Select_basic
package im.bool.a06_sort_algrithm;

import java.util.Arrays;

/**
 * #Author : ivanl001
 * #Date   : 2020/2/24 7:57 PM
 * #Desc   : 选择排序基础: 这里是第一轮从第二个数开始,如果发现比第一个数小,先标记为最小,然后往后看,直到最后,那么把第一个数和标记的最小数互换
 *                      第二轮从第三个数开始,如果发现比第一个数小,先标记为最小,然后往后看,直到最后,那么把第二个数和标记的最小数互换
 *                      依次下去,直至最后一个数字
 **/
public class a06_03_Select_basic {
    public static void main(String[] args) {

        int[] nums = {3, 9, -1, -2, -10};

        int min = nums[0];
        int index = 0;

      	//第一轮
        min = nums[0];
        index = 0;
        for (int i = 0 + 1; i < nums.length; i++) {
            if (min > nums[i]) {
                min = nums[i];
                index = i;
            }
        }
        if (index > 0) {
            nums[index] = nums[0];
            nums[0] = min;
        }
        System.out.println(Arrays.toString(nums));


				//第二轮
        min = nums[1];
        index = 1;
        for (int i = 1 + 1; i < nums.length; i++) {
            if (min > nums[i]) {
                min = nums[i];
                index = i;
            }
        }
        if (index > 1) {
            nums[index] = nums[1];
            nums[1] = min;
        }
        System.out.println(Arrays.toString(nums));

				//第三轮
        min = nums[2];
        index = 2;
        for (int i = 2 + 1; i < nums.length; i++) {
            if (min > nums[i]) {
                min = nums[i];
                index = i;
            }
        }
        if (index > 2) {
            nums[index] = nums[2];
            nums[2] = min;
        }
        System.out.println(Arrays.toString(nums));

				//第四轮
        min = nums[3];
        index = 3;
        for (int i = 3 + 1; i < nums.length; i++) {
            if (min > nums[i]) {
                min = nums[i];
                index = i;
            }
        }
        if (index > 3) {
            nums[index] = nums[3];
            nums[3] = min;
        }
        System.out.println(Arrays.toString(nums));
    }
}
a06_04_Select
package im.bool.a06_sort_algrithm;

import java.util.Arrays;

/**
 * #Author : ivanl001
 * #Date   : 2020/2/24 8:31 PM
 * #Desc   : TODO
 **/
public class a06_04_Select {
    public static void main(String[] args) {

        /*int[] nums = {3, 9, -1, -2, -10, 30, -5, 100, 30, 3, -4, 33};
        selectSort(nums);
        System.out.println(Arrays.toString(nums));*/

        int[] nums = new int[80000];
        for (int i = 0; i < 80000; i++) {
            nums[i] = (int) (Math.random() * 80000);
        }

        long startTime = System.currentTimeMillis();
        selectSort(nums);
        long endTime = System.currentTimeMillis();
        //2s左右, 比冒泡算法要快不少
        System.out.println(endTime-startTime);
        System.out.println(Arrays.toString(nums));
    }

    public static void selectSort(int[] nums) {

        int min;
        int index;

        //因为有两轮循环,所以选择排序的时间复杂度是时间复杂度是O(n^2)
        for (int i = 0; i < nums.length - 1; i++) {
//            System.out.println("iiii");
            min = nums[i];
            index = i;

            for (int j = i + 1; j < nums.length; j++) {
                if (min > nums[j]) {
                    min = nums[j];
                    index = j;
                }
            }

            if (index > i) {
                nums[index] = nums[i];
                nums[i] = min;
            }
        }
    }
}

4, 插入排序

1,第一轮把第二个数和第一个比较, 如果比第一个小, 那么把第一个后移一位,然后把第二个数赋值到第一位上
2,第二轮把第三个数和第二个数比较,如果比第二个小,那么把第二个数后移一位,然后再和第一个数比较,如果还比第一个数小(否则把第三个数赋值到第二位上),再把第一个数后移一位,把第三个数赋值到第一位上。
3,依次执行如上逻辑
4,n个数字经过(n-1)轮插入,即可保证有序

注意:插入是先在前面的数据中找到应该插入的位置,最后才会插入

这个和冒泡有点类似, 不过冒泡是先替换,然后再冒泡。插入时先找到最后位置,最后再替换。

插入的重点是: 把后面的一次往后移动一位,空出需要插入的,然后插入即可

a06_05_Insert_basic
package im.bool.a06_sort_algrithm;

import java.util.Arrays;

/**
 * #Author : ivanl001
 * #Date   : 2020/2/25 9:24 AM
 * #Desc   : 插入排序算法的推导过程
 **/
public class a06_05_Insert_basic {
    public static void main(String[] args) {
        int[] nums = {3, 9, -1, -2, 10};

        //插入排序思路:
        /**
         * 1,第一轮把第二个数和第一个比较, 如果比第一个小, 那么把第一个后移一位,然后把第二个数赋值到第一位上
         * 2,第二轮把第三个数和第二个数比较,如果比第二个小,那么把第二个数后移一位,然后再和第一个数比较,如果还比第一个数小(否则把第三个数赋值到第二位上),再把第一个数后移一位,把第三个数赋值到第一位上。
         * 3,依次执行如上逻辑
         * 4,n个数字经过(n-1)轮插入,即可保证有序
         */
        //即将被插入的数字
        int insertValue = nums[1];
        //这个是要找的待插入序号
        int indexToInsert = 1 - 1;
        while (indexToInsert >= 0 && insertValue < nums[indexToInsert]) {
            //如果有比待插入数据要大的, 那么就把该数据后移一位
            nums[indexToInsert + 1] = nums[indexToInsert];
            indexToInsert--;
        }
        nums[indexToInsert+1] = insertValue;
        System.out.println(indexToInsert);
        System.out.println("第一轮:" + Arrays.toString(nums));

        //即将被插入的数字
        insertValue = nums[2];
        //这个是要找的待插入序号
        indexToInsert = 2 - 1;
        while (indexToInsert >= 0 && insertValue < nums[indexToInsert]) {
            //如果有比待插入数据要大的, 那么就把该数据后移一位
            nums[indexToInsert + 1] = nums[indexToInsert];
            //因为这里先减,后循环,所以后面出了循环需要再加1加回来
            indexToInsert--;
        }
        nums[indexToInsert+1] = insertValue;
        System.out.println(indexToInsert);
        System.out.println("第二轮:" + Arrays.toString(nums));

        //即将被插入的数字
        insertValue = nums[3];
        //这个是要找的待插入序号
        indexToInsert = 3 - 1;
        while (indexToInsert >= 0 && insertValue < nums[indexToInsert]) {
            //如果有比待插入数据要大的, 那么就把该数据后移一位
            nums[indexToInsert + 1] = nums[indexToInsert];
            //因为这里先减,后循环,所以后面出了循环需要再加1加回来
            indexToInsert--;
        }
        nums[indexToInsert+1] = insertValue;
        System.out.println(indexToInsert);
        System.out.println("第三轮:" + Arrays.toString(nums));

        //即将被插入的数字
        insertValue = nums[4];
        //这个是要找的待插入序号
        indexToInsert = 4 - 1;
        while (indexToInsert >= 0 && insertValue < nums[indexToInsert]) {
            //如果有比待插入数据要大的, 那么就把该数据后移一位
            nums[indexToInsert + 1] = nums[indexToInsert];
            //因为这里先减,后循环,所以后面出了循环需要再加1加回来
            indexToInsert--;
        }
        nums[indexToInsert+1] = insertValue;
        System.out.println(indexToInsert);
        System.out.println("第四轮:" + Arrays.toString(nums));
    }
}
a06_06_Insert
package im.bool.a06_sort_algrithm;

import java.util.Arrays;

/**
 * #Author : ivanl001
 * #Date   : 2020/2/25 10:11 AM
 * #Desc   : 插入排序法
 **/
public class a06_06_Insert {

    public static void main(String[] args) {
        /*int[] nums = {3, 9, -1, -2, 10, -3, 0};

        insert(nums);
        System.out.println(Arrays.toString(nums));*/

        int[] nums = new int[80000];
        for (int i = 0; i < 80000; i++) {
            nums[i] = (int) (Math.random() * 80000);
        }

        long startTime = System.currentTimeMillis();
        insert(nums);
        long endTime = System.currentTimeMillis();
        //1s左右, 冒泡大概9s,选择大概2s,还是插入排序算法速度最快。
        System.out.println(endTime-startTime);
        //System.out.println(Arrays.toString(nums));
    }

    public static void insert(int[] nums) {
        for (int i=1; i<nums.length; i++) {
            //即将被插入的数字
            int insertValue = nums[i];
            //这个是要找的待插入序号
            int indexToInsert = i - 1;
            while (indexToInsert >= 0 && insertValue < nums[indexToInsert]) {
                //如果有比待插入数据要大的, 那么就把该数据后移一位
                nums[indexToInsert + 1] = nums[indexToInsert];
                indexToInsert--;
            }
            //这个地方可以做个判断,如果相同,那本来就是在正确的位置
            if (indexToInsert + 1 != i) {
                nums[indexToInsert+1] = insertValue;
            }
            /*System.out.println(indexToInsert);
            System.out.println("第" + i + "轮:" + Arrays.toString(nums));*/
        }
    }
}

5, shell(希尔)排序-插入排序的优化

shell排序是插入排序的优化,以减少数据插入之前为了找到插入位置而可能后移次数过多的问题

shell排序的时候有两种方式:

1,交换法。直接进行交换, 速度慢

2,移动法,先移动,而不是直接交换。速度快,超级快!80万只需要20ms左右。

下面图中有点说的好像不对:分组之后排序的时候, 用的应该不是插入排序,而是冒泡排序吧

不过有点需要留意:

shell排序的时候循环次数比插入排序循环次数要多,只不过shell排序的插入次数少了, 所以才快的

image-20210501150437040

这个时间复杂度是n*logn,相对n的平方还是要小的

a06_08_Shell_01_exchange(并不是shell排序)
package im.bool.a06_sort_algrithm;

import java.util.Arrays;

/**
 * #Author : ivanl001
 * #Date   : 2020/2/25 11:55 AM
 * #Desc   : 希尔排序-插入排序的优化算法: 直接交换,其实不是很好,效率有限
 *           希尔排序的时间复杂度是nlogn,比n^2要好一些
 **/
public class a06_08_Shell_01_exchange {

    public static void main(String[] args) {

        int[] nums = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
        shellSort(nums);

        /*int[] nums = new int[80000];
        for (int i = 0; i < 80000; i++) {
            nums[i] = (int) (Math.random() * 80000);
        }

        long startTime = System.currentTimeMillis();
        shellSort(nums);
        long endTime = System.currentTimeMillis();
        //这里用了5s左右, 插入排序1s左右, 冒泡大概9s,选择大概2s,还是插入排序算法速度最快。
        //这里本来是插入排序的优化,之所以比插入还要慢, 是因为这里直接更换,而插入是先移动,最后才替换。所以我们这里后续需要再优化一下,
        //把交换改成先移动,最后再更换
        System.out.println(endTime-startTime);*/
        System.out.println(Arrays.toString(nums));

    }


    public static void shellSort(int[] nums) {
        //插入排序的过程中,因为需要数据后移,在最差的情况下,每次数据都需要后移, 这种效率是不高的
        //所以就有了希尔排序
        int temp = 0;

        int m=0;
        for (int gap = nums.length / 2; gap > 0; gap /= 2) {
            //第一轮排序,将10个数据分成了5组
            for (int i = gap; i < nums.length; i++) {
                for (int j = i - gap; j >= 0; j -= gap) {
                    if (nums[j] > nums[j + gap]) {
                         
                        nums[j] = nums[j + gap];
                        nums[j + gap] = temp;
                    }
                }
            }
            //System.out.println("第 " + (m++) + " 轮:" + Arrays.toString(nums));
        }
    }
}
a06_08_Shell_02_move
package im.bool.a06_sort_algrithm;

import sun.plugin2.ipc.windows.WindowsIPCFactory;

import java.util.Arrays;

/**
 * #Author : ivanl001
 * #Date   : 2020/2/25 11:55 AM
 * #Desc   : 希尔排序-插入排序的优化算法: 采用希尔排序移动法
 **/
public class a06_08_Shell_02_move {

    public static void main(String[] args) {

        /*int[] nums = {12, -10, 100, 8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
        shellSort01(nums);
        System.out.println(Arrays.toString(nums));*/


        int[] nums = new int[80000];
        for (int i = 0; i < 80000; i++) {
            nums[i] = (int) (Math.random() * 80000);
        }

        long startTime = System.currentTimeMillis();
        shellSort01(nums);
        long endTime = System.currentTimeMillis();
        //这里用了21ms左右, shell排序如果用前面的交换,大概5s, 插入排序1s左右, 冒泡大概9s,选择大概2s
        //所以移位法速度提升简直是非常非常大的
        System.out.println(endTime-startTime);
        //System.out.println(Arrays.toString(nums));
    }


    public static void shellSort01(int[] nums) {
        //插入排序的过程中,因为需要数据后移,在最差的情况下,每次数据都需要后移, 这种效率是不高的
        //所以就有了希尔排序
        //int temp = 0;

        int m = 0;
        for (int gap = nums.length / 2; gap > 0; gap /= 2) {

            //第一轮排序,将10个数据分成了5组
            for (int i = gap; i < nums.length; i++) {

                int j = i;
                int temp = nums[j];

                //教程中这里多判断了一个条件, 个人感觉不是很必要,所以直接舍弃了
                //下面的移动过程可以参考插入算法
                while ((j - gap >= 0) && temp < nums[j - gap]) {
                    //先把小的移动到后面
                    nums[j] = nums[j - gap];
                    j -= gap;
                }
                nums[j] = temp;

            }
            //System.out.println("第 " + (m++) + " 轮:" + Arrays.toString(nums));
        }
    }
}

6, 归并排序

image-20200229094101040

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值