插入排序存在的问题
例如数组arr = {2,3,4,5,6,1} 这时需要插入的数1的过程是:
{2,3,4,5,6,6}
{2,3,4,5,5,6}
{2,3,4,4,5,6}
{2,3,3,4,5,6}
{2,2,3,4,5,6}
{1,2,3,4,5,6}
当需要插入的数是较小的数时,后移的次数明显增多,效率低。
希尔排序
希尔排序是希尔提出的一种排序算法。它是一种插入排序。是简单插入排序经过改良后的一个版本,也称之为缩小增量排序。
基本思想
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个数组恰被分成一组,算法终止。
代码推导(交换法)
package sort;
import java.util.Arrays;
public class ShellSort {
public static void main(String[] args) {
int[] arr = {8,9,1,7,2,3,5,4,6,0};
shellSort(arr);
}
public static void shellSort(int[] arr){
int temp = 0;
//第一轮排序
//10个数据分成5组
for (int i = 5; i < arr.length; i++){
//遍历各组中所有的元素(共5组,每组有2个元素)
for (int j = i-5; j >= 0; j-=5 ){
//如果当前元素大于相隔步长的元素,交换
if(arr[j] > arr[j+5]){
temp = arr[j];
arr[j] = arr[j+5];
arr[j+5] = temp;
}
}
}
System.out.println("第一轮排序");
System.out.println(Arrays.toString(arr));
//第二轮排序
//10个数据分成2组
for (int i = 2; i < arr.length; i++){
//遍历各组中所有的元素(共5组,每组有2个元素)
for (int j = i-2; j >= 0; j-=2 ){
//如果当前元素大于相隔步长的元素,交换
if(arr[j] > arr[j+2]){
temp = arr[j];
arr[j] = arr[j+2];
arr[j+2] = temp;
}
}
}
System.out.println("第二轮排序");
System.out.println(Arrays.toString(arr));
//第三轮排序
//10个数据分成1组
for (int i = 1; i < arr.length; i++){
//遍历各组中所有的元素(共5组,每组有2个元素)
for (int j = i-1; j >= 0; j-=1 ){
//如果当前元素大于相隔步长的元素,交换
if(arr[j] > arr[j+1]){
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
System.out.println("第三轮排序");
System.out.println(Arrays.toString(arr));
}
}
最终代码(交换法)
package sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class ShellSort {
public static void main(String[] args) {
int[] arr = new int[80000];
for (int i=0; i<80000; i++){
arr[i] = (int)(Math.random()*8000000); //生成[0,8000000]的数
}
Date start = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String startS = sdf.format(start);
System.out.println("排序前的时间是="+startS);
shellSort(arr);
Date end = new Date();
String endS= sdf.format(end);
System.out.println("排序后的时间是="+endS);
}
public static void shellSort(int[] arr){
int temp = 0;
for (int gap = arr.length/2; gap > 0; gap /= 2){
for (int i = gap; i < arr.length; i++){
//遍历各组中所有的元素(共5组,每组有2个元素)
for (int j = i-gap; j >= 0; j-=gap ){
//如果当前元素大于相隔步长的元素,交换
if(arr[j] > arr[j+gap]){
temp = arr[j];
arr[j] = arr[j+gap];
arr[j+gap] = temp;
}
}
}
}
}
}
插入法
package sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class ShellSort {
public static void main(String[] args) {
int[] arr = new int[80000];
for (int i=0; i<80000; i++){
arr[i] = (int)(Math.random()*8000000); //生成[0,8000000]的数
}
Date start = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String startS = sdf.format(start);
System.out.println("排序前的时间是="+startS);
shellSort2(arr);
Date end = new Date();
String endS= sdf.format(end);
System.out.println("排序后的时间是="+endS);
}
//插入法
public static void shellSort2(int[] arr){
for (int gap = arr.length/2; gap > 0; gap /= 2){
//从第gap个元素,逐个对其所在的组进行直接插入
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;
}
}
}
}
}