插入排序与希尔排序
插入排序:将待排序列的第一个元素看为有序序列,后面的元素看为未排序序列,从头到尾依次扫描未排序序列,将未排序序列插入到有序序列的合适位置。
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
1.插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;
2.希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。
插入排序代码实现
package com.datestructures.tensort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class InsertionSort {
//插入排序
/**
* 假想有两个列表,一个有序,一个无序 有序列表有第一个元素,其余的在无序列表
* 每次从无序列表中取一个元素插入的有序列表的适当位置
* @param args
*
* 当需要插入的数是较小的数时,后移的次数明显增多,对效率有影响.
*/
public static void main(String[] args) {
//创建要给80000个的随机数组
int[] arr = new int[80000];
for (int i = 0; i < 80000; i++) {
arr[i] = (int) (Math.random()*8000000);//生成一个[0,8000000)的数
}
System.out.println("排序前");
Date date1 = new Date();
SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strdate1 = simpleDateFormat1.format(date1);
System.out.println("排序前的时间是:"+strdate1);
insertionSort(arr);
System.out.println("排序后");
Date date2 = new Date();
SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strdate2 = simpleDateFormat2.format(date2);
System.out.println("排序后的时间是:"+strdate2);
//排序前
//排序前的时间是:2023-04-24 10:33:49
//排序后
//排序后的时间是:2023-04-24 10:33:49
}
public static void insertionSort(int[] arr){
for (int i = 1; i < arr.length ; i++) {
int insertVal = arr[i];//待插入的数据
int inserIndex = i-1;//待插入数据前一个索引
while (inserIndex>=0&&insertVal<arr[inserIndex]){
//inserIndex>=0 防止索引越界
//insertVal<arr[inserIndex] 待插入数据小于有序列表中最后一位的数据则选择合适的位置插入
//先将有序列表最后一个数据后移
arr[inserIndex+1]=arr[inserIndex];
inserIndex--;//自减与有序列表中的前一个数据进行比较
//以此循环,直到insertVal>arr[inserIndex]
}
//此时 要插入的位置的索引为(inserIndex+1)
arr[inserIndex+1] = insertVal;
//System.out.println("排序后:"+ Arrays.toString(arr));
}
}
}
希尔排序代码实现
package com.datestructures.tensort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class ShellSort {
//希尔排序
//希尔排序的思想
//将原数组先二分然后以步长为原数组的长度除以2进行排序
//再将排序的数组再次按原数组的长度除以4进行排序
//以此往复,直到步长为1进行排序后就是所求
public static void main(String[] args) {
//int[] arr = {8,9,1,7,2,3,5,4,6,0};
//创建要给80000个的随机数组
int[] arr = new int[80000];
for (int i = 0; i < 80000; i++) {
arr[i] = (int) (Math.random() * 8000000);//生成一个[0,8000000)的数
}
System.out.println("排序前");
Date date1 = new Date();
SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strdate1 = simpleDateFormat1.format(date1);
System.out.println("排序前的时间是:" + strdate1);
shellSort1(arr);
System.out.println("排序后");
Date date2 = new Date();
SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strdate2 = simpleDateFormat2.format(date2);
System.out.println("排序后的时间是:" + strdate2);
//交换法
//排序前
//排序前的时间是:2023-04-24 10:30:03
//排序后
//排序后的时间是:2023-04-24 10:30:08
//移位法
//排序前
//排序前的时间是:2023-04-24 10:47:45
//排序后
//排序后的时间是:2023-04-24 10:47:45
}
public static void shellSort(int[] arr) {
int count = 0;//计数器
for (int gap = arr.length / 2; gap > 0; gap /= 2) {//每次循环更新步长
for (int i = gap; i < arr.length; i++) {//从arr[gap]开始于arr[i-gap]开始比较 比较完后i++
for (int j = i - gap; j >= 0; j -= gap) {//将arr[i]与同一组前面元素相比较,插入适当位置
if (arr[j] > arr[j + gap]) {
//交换法 交换耗时间 而插入法 不需要交换
//优化为移位法
int temp = arr[j];
arr[j] = arr[j + gap];
arr[j + gap] = temp;
}
}
}
//System.out.println("第"+(++count)+"轮排序后"+ Arrays.toString(arr));
}
}
/**
* 优化后的希尔排序
* 移位法
*
* @param arr
*/
public static void shellSort1(int[] arr) {
int count = 0;
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < arr.length; i++) {//从arr[gap]开始于arr[i-gap]开始比较 比较完后i++
int inertIndex = i;
int inertVal = arr[inertIndex];
if (arr[inertIndex] < arr[inertIndex - gap]) {
while (inertIndex - gap >= 0 && inertVal < arr[inertIndex - gap]) {
//移动
arr[inertIndex] = arr[inertIndex-gap];
inertIndex-=gap;
}
//当退出while循环,就找到了插入的位置
arr[inertIndex] = inertVal;
}
}
//System.out.println("第"+(++count)+"轮排序后"+ Arrays.toString(arr));
}
}
}