插入排序
基本思想:
- 类似玩扑克牌开始序牌时,新安排的无序牌与最后一个牌对比
- 倒数第二张牌>新安排>最后一个牌
- 新安排
- 倒数第三张牌>新安排>倒数第二张牌>最后一个牌
思路: - 直接先看第三次插入{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);
}
}