【数据结构】排序算法-插入排序&希尔排序

排序算法-插入排序&希尔排序

插入排序

基本思想:

  • 类似玩扑克牌开始序牌时,新安排的无序牌与最后一个牌对比
  • 倒数第二张牌>新安排>最后一个牌
  • 新安排
  • 倒数第三张牌>新安排>倒数第二张牌>最后一个牌
    在这里插入图片描述
    思路:
  • 直接先看第三次插入{3,17,25,14,20,9}
  • 这时拿14来插
  • 先把14用temp存着
  • 再14和25相比,25应该后移
  • 所以这时,是25后移,不是交换!!!
  • 25就赋值给自己的index+1
  • 但是这时index也还是25,因为刚刚不是交换!14这个数在temp存着,不怕,继续拿temp去比!
  • {3,17,25,25,20,9}
  • 14这时和17比,17也应该后移,17就赋值给自己的index+1,17原来的index也不变
  • {3,17,17,25,20,9}
  • temp再和3比,发现不能和3换了,所以就跟17的原index交换,这时才交换哦!

代码实现:
原始数组:{110,34,119,1}

package com.fly.o;

import java.util.Arrays;

/**
 * @Title: 插入排序
 * @author: Fly
 * @date: 2020/3/29 - 14:52
 */
public class InsertSort {
    public static void main(String[] args) {
        insertSort();
     }
    public static void insertSort(){
        int[] arr={110,34,119,1};
        //第一轮
        int insertVal=arr[1];//定义待插入的数
        int insertIndex=1-1;//arr[1]前面那个数的下标
        //给insertVal找到插入的位置
        //1.insertIndex>=0 保证在给insertVal 找插入位置,不越界
        //2.insertVal < arr[insertIndex] 要插入的值的确比前标值小,也就是没有找到插入位置
        //3.就需要将arr[insertIndex]后移
        while (insertIndex>=0 && insertVal<arr[insertIndex]){
            arr[insertIndex+1]=arr[insertIndex];//{110,110,119,1}
            insertIndex--;//第一轮时就是0--为-1
        }
        //当退出while循环时,也就是找到插入的位置
        // insertIndex这时为-1,往后移一位 insertIndex+1=0
         arr[insertIndex+1]=insertVal;//{34,110,119,1}
        System.out.println(Arrays.toString(arr));

        //第二轮
        insertVal=arr[2];//定义待插入的数:119
        insertIndex=2-1;//arr[1]前面那个数的下标
        //给insertVal找到插入的位置
        //1.insertIndex>=0 保证在给insertVal 找插入位置,不越界
        //2.insertVal < arr[insertIndex] 要插入的值的确比前标值小,也就是没有找到插入位置
        //3.就需要将arr[insertIndex]后移
        while (insertIndex>=0 && insertVal<arr[insertIndex]){
            arr[insertIndex+1]=arr[insertIndex];
            insertIndex--;//第一轮时就是0--为-1
        }
        //当退出while循环时,也就是找到插入的位置
        // insertIndex这时为-1,往后移一位 insertIndex+1=0
        arr[insertIndex+1]=insertVal;//119还是arr[2]
        System.out.println(Arrays.toString(arr));

        //第三轮
        insertVal=arr[3];//定义待插入的数:1
        insertIndex=3-1;//arr[1]前面那个数的下标
        //给insertVal找到插入的位置
        //1.insertIndex>=0 保证在给insertVal 找插入位置,不越界
        //2.insertVal < arr[insertIndex] 要插入的值的确比前标值小,也就是没有找到插入位置
        //3.就需要将arr[insertIndex]后移
        while (insertIndex>=0 && insertVal<arr[insertIndex]){
            arr[insertIndex+1]=arr[insertIndex];//{34,110,119,119}   {34,110,110,119}   {34,34,110,119}
            insertIndex--;//第一轮时就是0--为-1   1:110                0: 34               -1
        }
        //当退出while循环时,也就是找到插入的位置
        // insertIndex这时为-1,往后移一位 insertIndex+1=0
        arr[insertIndex+1]=insertVal;//arr[0]=1   {1,34,110,119}
        System.out.println(Arrays.toString(arr));
    }
}

在这里插入图片描述
啊啊啊啊啊啊啊啊啊啊啊我的脑子,恨不得我自己就是Debug
重构第一二三轮:

public class InsertSort {
    public static void main(String[] args) {
        insertSort1();
     }

    private static void insertSort1() {
        int[] arr={110,34,119,1};
        for (int i = 1; i < arr.length; i++) {
            int insertVal=arr[i];//定义待插入的数
            int insertIndex=i-1;//arr[1]前面那个数的下标
            //给insertVal找到插入的位置
            //1.insertIndex>=0 保证在给insertVal 找插入位置,不越界
            //2.insertVal < arr[insertIndex] 要插入的值的确比前标值小,也就是没有找到插入位置
            //3.就需要将arr[insertIndex]后移
            while (insertIndex>=0 && insertVal<arr[insertIndex]){
                arr[insertIndex+1]=arr[insertIndex];
                insertIndex--;
            }
            //当退出while循环时,也就是找到插入的位置
            arr[insertIndex+1]=insertVal;
            System.out.println(Arrays.toString(arr));
        }
    }

8万个随机数排序耗时1秒
在这里插入图片描述
如果题目改成从大到小,则需要把代码改成:

  while (insertIndex>=0 && insertVal>arr[insertIndex]){
                arr[insertIndex+1]=arr[insertIndex];
                insertIndex--;
            }

希尔排序

交换式

我觉得交换式就是分组冒泡(相邻逆序,步长为1),用步长每次只要保证把最小(极值)往前排

package com.fly.sort;

import java.util.Arrays;

/**
 * @Title: 希尔排序-交换式
 * @author: Fly
 * @date: 2020/3/31 - 13:24
 */
public class ShellSort_Exchange {
    public static void main(String[] args) {
        int[] arr={8,9,1,7,2,3,5,4,6,0};
//        infer(arr);
        int[] arr1 = TimeTest.newArr();
        TimeTest.timeTestBefore();
        shellSort(arr1);
        TimeTest.timeTestAfter();
    }

    private static void shellSort(int[] arr) {
        int count=0;
        for (int gap=arr.length/2;gap>0;gap/=2){
            int temp=0;
            for (int i = gap; i < arr.length; i++) {
                //遍历各组中所有的元素(共5组,每组有2个元素)
                for (int j=i-gap;j>=0;j-=gap){
                    //比如:当8大于8后面的第5位的3时,就交换
                    if (arr[j]>arr[j+gap]){
                        temp=arr[j];
                        arr[j]=arr[j+gap];
                        arr[j+gap]=temp;
                    }
                }
            }
//            System.out.println("希尔排序第"+(++count)+"遍:"+Arrays.toString(arr));
        }
    }

    private static void infer(int[] arr) {
        //希尔排序的第一轮
        //因为第一轮排序,是将10个数据分成10/2=5组
        int temp=0;
        for (int i = 5; i < arr.length; i++) {
            //遍历各组中所有的元素(共5组,每组有2个元素)
            for (int j=i-5;j>=0;j-=5){
                //比如:当8大于8后面的第5位的3时,就交换
                if (arr[j]>arr[j+5]){
                    temp=arr[j];
                    arr[j]=arr[j+5];
                    arr[j+5]=temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
        //第二轮
        //5/2=2组
        for (int i = 2; i < arr.length; i++) {
            //遍历各组中所有的元素(共5组,每组有2个元素)
            for (int j=i-2;j>=0;j-=2){
                //比如:当8大于8后面的第5位的3时,就交换
                if (arr[j]>arr[j+2]){
                    temp=arr[j];
                    arr[j]=arr[j+2];
                    arr[j+2]=temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
    }
}

8万个随机数排序耗时7秒
在这里插入图片描述
慢的原因,就是每次一旦发现逆序就交换,发现一次交换一次,交换次数太多,但是只是把一个最小值交换到前面,效率低,所以改善方法就是借插入排序的思想,不要发现一个交换一个。所以先不交换,插入后移.

移动法

希尔排序就是比插入排序缩小增量

package com.fly.sort;

import java.util.Arrays;

/**
 * @Title: 希尔排序-移动法
 * @author: Fly
 * @date: 2020/3/31 - 15:04
 */
public class ShellSort_Move {
    public static void main(String[] args) {
        int[] arr1 = TimeTest.newArr();
        TimeTest.timeTestBefore();
        shellSort(arr1);
        TimeTest.timeTestAfter();
    }

    private static void shellSort(int[] arr) {
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            for (int i = gap; i < arr.length; i++) {
                int j = i;
                int temp = arr[j];
                if (arr[j] < arr[j - gap]) {
                    while (j - gap >= 0 && temp < arr[j - gap]) {
                        arr[j] = arr[j-gap];
                        j-=gap;
                    }
                    arr[j]=temp;
                }
            }
        }
//        System.out.println(Arrays.toString(arr));
//            System.out.println("希尔排序第"+(++count)+"遍:"+Arrays.toString(arr));
    }
}

天啊!用时不用一秒!!
在这里插入图片描述

8000测试代码

package com.fly.sort;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Title: 用时测试器
 * @author: Fly
 * @date: 2020/3/29 - 16:33
 */
public class TimeTest {
    public static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static int[] newArr(){
        int[] arr=new int[80000];
        for (int i = 0; i < 80000; i++) {
            arr[i]=(int)(Math.random()*100000);
        }
        return arr;
    }
    public static void timeTestBefore(){

        Date date = new Date();
        String format = simpleDateFormat.format(date);
        System.out.println("排序前时间是:"+format);
    }
    public static void timeTestAfter(){
        Date date1 = new Date();
        String format1 = simpleDateFormat.format(date1);
        System.out.println("排序后时间是:"+format1);
    }


}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值