前言:
大家好,上一篇博客带大家学习如何编写十大排序算法中的三大简单排序,那么今天带给大家的学习内容是十大排序算法中的希尔排序算法
1.1 希尔排序基础概念
在编写希尔排序算法之前,我们首先简单了解一下希尔排序的基本概念和排序的流程,会对算法的编写很有帮助!
1.1.1 希尔排序基本概念
1.1.2 希尔排序执行流程
从数组中下标0位置开始,首先按照每隔4位(从当前下标下一位开始计算)选出一位数,然后将这些间隔为4的数进行排序
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|
9 | 6 | 11 | 3 | 5 | 12 | 8 | 7 | 10 | 15 | 14 | 4 | 1 | 13 | 2 | 1 | 6 | 11 | 3 | 5 | 12 | 8 | 7 | 9 | 15 | 14 | 4 | 10 | 13 | 2 |
从数组下标1位置开始,重复上述操作
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|
1 | 6 | 11 | 3 | 5 | 12 | 8 | 7 | 9 | 15 | 14 | 4 | 10 | 13 | 2 | 1 | 6 | 11 | 3 | 5 | 12 | 8 | 7 | 9 | 13 | 14 | 4 | 10 | 15 | 2 |
从数组下标2位置开始,重复上述步骤
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|
1 | 6 | 11 | 3 | 5 | 12 | 8 | 7 | 9 | 13 | 14 | 4 | 10 | 15 | 2 | 1 | 6 | 2 | 3 | 5 | 12 | 8 | 7 | 9 | 13 | 11 | 4 | 10 | 15 | 14 |
从数组下标3位置开始,重复上述步骤
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|
1 | 6 | 2 | 3 | 5 | 12 | 8 | 7 | 9 | 13 | 11 | 4 | 10 | 15 | 14 | 1 | 6 | 2 | 3 | 5 | 12 | 8 | 4 | 9 | 13 | 11 | 7 | 10 | 15 | 14 |
缩小间隔为2继续进行新一轮的排序,再将间隔分别调整为2继续进行排序,直到最后间隔为1排序完结束
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|
1 | 6 | 2 | 3 | 5 | 12 | 8 | 4 | 9 | 13 | 11 | 7 | 10 | 15 | 14 | 1 | 6 | 2 | 3 | 5 | 12 | 8 | 4 | 9 | 13 | 11 | 7 | 10 | 15 | 14 |
间隔为2的红色数字先排序,然后间隔为2的橙色数字再排序
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|
1 | 6 | 2 | 3 | 5 | 12 | 8 | 4 | 9 | 13 | 11 | 7 | 10 | 15 | 14 | 1 | 6 | 2 | 3 | 5 | 12 | 8 | 4 | 9 | 13 | 10 | 7 | 11 | 15 | 14 | 1 | 3 | 2 | 4 | 5 | 6 | 8 | 7 | 9 | 12 | 10 | 13 | 11 | 15 | 14 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|
1 | 3 | 2 | 4 | 5 | 6 | 8 | 7 | 9 | 12 | 10 | 13 | 11 | 15 | 14 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
1.2 希尔排序算法实现
1.2.1 希尔排序代码实现
1.初次编写希尔排序
由于希尔排序是插入排序的改进版,如果编写时没有思路,可以先写一个插入排序,然后在其基础上慢慢修改
package com.kuang.review2;
public class ShellSort {
public static void main(String[] args) {
int[] arr = {9,6,11,3,5,12,8,7,10,15,14,4,1,13,2};
sort1(arr);
System.out.println("最终排序结果为:");
print(arr);
}
static void sort1(int[] arr) {
for (int i = 1; i < arr.length; i++) {
for (int j = i; j > 0; j--) {
if(arr[j] < arr[j-1]) {
swap(arr, j,j-1);
}
}
System.out.println("第"+i+"轮排序结果为:");
print(arr);
}
}
static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
static void print(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]+" ");
}
}
}
结果:元素从小到大排列,排序结果正确!
2.希尔排序算法改进1
在插入排序算法基础上,引入排序的间隔,将其修改为希尔排序
package com.kuang.review2;
public class ShellSort {
public static void main(String[] args) {
int[] arr = {9,6,11,3,5,12,8,7,10,15,14,4,1,13,2};
sort2(arr);
System.out.println("最终排序结果为:");
print(arr);
}
static void sort2(int[] arr) {
int gap = 4;
for (int i = gap; i < arr.length; i++) {
for (int j = i; j > gap-1 ; j-=gap) {
if(arr[j] < arr[j-gap]) {
swap(arr, j,j-gap);
}
}
System.out.println("第"+i+"轮排序结果为:");
print(arr);
}
}
static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
static void print(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]+" ");
}
}
}
结果:与间隔为4的排序结果相同!
3.希尔排序算法改进2
在希尔排序算法第一版基础上,将排序间隔修改为动态变化
package com.kuang.review2;
public class ShellSort {
public static void main(String[] args) {
int[] arr = {9,6,11,3,5,12,8,7,10,15,14,4,1,13,2};
sort3(arr);
System.out.println("最终排序结果为:");
print(arr);
}
static void sort3(int[] arr) {
int num = 0;
for (int gap = arr.length/2; gap > 0; gap/=2) {
for (int i = gap; i < arr.length; i++) {
for (int j = i; j > gap-1 ; j-=gap) {
if(arr[j] < arr[j-gap]) {
swap(arr, j,j-gap);
}
}
}
num++;
System.out.println("间隔为"+gap+"时, 第"+ num +"轮排序结果为:");
print(arr);
}
}
static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
static void print(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]+" ");
}
}
}
结果:元素从小到大排序,排序结果正确!
4. 希尔排序算法改进3
在希尔排序改进第二版基础上,使用Knuth序列进行优化
package com.kuang.review2;
public class ShellSort {
public static void main(String[] args) {
int[] arr = {9,6,11,3,5,12,8,7,10,15,14,4,1,13,2};
sort4(arr);
System.out.println("最终排序结果为:");
print(arr);
}
static void sort4(int[] arr) {
int num = 0;
int h = 1;
while(h <= arr.length/3) {
h = h*3 + 1;
}
for (int gap = h; gap > 0; gap/=2) {
for (int i = gap; i < arr.length; i++) {
for (int j = i; j > gap-1 ; j-=gap) {
if(arr[j] < arr[j-gap]) {
swap(arr, j,j-gap);
}
}
}
num++;
System.out.println("间隔为"+gap+"时, 第"+ num +"轮排序结果为:");
print(arr);
}
}
static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
static void print(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]+" ");
}
}
}
结果:元素从小到大排序,排序结果正确!
1.2.2 使用对数器进行检验
package com.kuang.test05;
import java.util.Arrays;
import java.util.Random;
public class DataChecker {
static int[] generateRandomArray() {
Random ran = new Random();
int[] arr = new int[100000];
for (int i = 0; i < arr.length; i++) {
arr[i] = ran.nextInt(100000);
}
return arr;
}
static void check() {
int[] arr = generateRandomArray();
int[] arr2 = new int[arr.length];
System.arraycopy(arr, 0, arr2, 0, arr.length);
Arrays.sort(arr);
ShellSort.sort(arr2);
boolean flag = true;
for(int i=0; i<arr2.length; i++) {
if(arr[i] != arr2[i])
flag = false;
}
System.out.println(false == true? "same":"different");
}
public static void main(String[] args) {
check();
}
}
1.3 希尔排序时间和空间复杂度
1.3.1 希尔排序时间复杂度
希尔排序的时间复杂度为n1.3,最坏时间复杂度为 n2,最好时间复杂度为 n
1.3.2 希尔排序空间复杂度
1.3.3 希尔排序稳定性
由于希尔排序没有出现创建新数组,所以空间复杂度为1
跳着排序,存在a和b两个值相等时,排序前a在前b在后,排序后b在前a在后,所以不稳定
好了,到这里,今天有关希尔排序算法的学习就结束了,欢迎大家讨论和学习!
参考视频链接:https://www.bilibili.com/video/BV14i4y1T7Af
|