希尔排序
个人理解
希尔排序的引入使得排序算法的时间复杂度突破了O(n2)
它巧妙的点在于事先让混乱的序列简单的趋于有序
具体做法为
让序列分层,只不过不是按顺序的分组,是跳跃的分组,比如,1,3,5,7,9是一个组,2,4,6,8,是一个。这样的话就打破了两两之间“排序”的关系。
分好组以后先进行组内排序,然后再次打乱进行分层,再次排序。
希尔排序的组内排序可以是冒泡排序,也可以是插入排序,本质都是组内先排好序,让整体快速趋于总体有序。(突然想起高中的熵增理论。。。)
但是冒泡排序的遍历起来并没有比冒泡排序要少,甚至还可能多,因此效率较差
对于插入排序来说,要方便很多,因为某些时候前面的交换能很快解决像{2,3,4,5,6,7,1}这种情况下的排序
希尔排序可以说是升级版的插入排序
代码写之
冒泡排序版(代码需优化,使用的是分组以后排序的思想):
package sort;
import java.util.Arrays;
public class ShellSort
{
public static void main(String[] args)
{
int[] arr =
{ 5, 3, 1, 2, 6, 4, 8 ,9,10,6,15,3,7};
shellSort(arr, 3);
System.out.println(Arrays.toString(arr));
}
// 从小到大
public static void shellSort(int[] arr, int InitArrNum)
{
// 先分组
int ArrNum = InitArrNum;// 子数组 的个数,一共有多少个序列 3
int SubNum = arr.length / ArrNum;// 每组的个数 总数 / 组数
// 排序的数
// 排序的序号 1, 1+3*1,1+3*2,1+3*3,1+3*4....
while (true)
{
for (int SubIndex = 0; SubIndex < ArrNum; SubIndex++)
{
// 冒泡排序,排序的是 1, 1+3*1,1+3*2,1+3*3,1+3*4....
// SubIndex 1 ArrNum 3
for (int i = 1; i < SubNum; i++)
{
for (int j = 0; j < SubNum - i; j++)
{
if (arr[SubIndex + ArrNum * j] > arr[SubIndex + ArrNum * (j + 1)])
{
dataSwap(arr, SubIndex + ArrNum * j, SubIndex + ArrNum * (j + 1));
}
}
}
}
ArrNum /= 2;
if (ArrNum==0)
{
break;
}
// 终止条件:分组为1
SubNum = arr.length / ArrNum;
}
}
/**
* 数组数据交换
*
* @param arr
* @param first
* @param second
*/
public static void dataSwap(int[] arr, int first, int second)
{
int temp;
temp = arr[first];
arr[first] = arr[second];
arr[second] = temp;
}
}
插入排序版(代码参考了尚硅谷),发现他们的遍历和我一开始思考的先分组组内排序的思想略有差异,他们遍历的方法是按数组依次遍历,每次比较大自己increase的。
同冒泡算法不同的是,插入是寻找自己应该到的位置,其他的位置往后移动。因为冒泡的话每次比较,如果逆序的话,要进行三次赋值。然而插入只需要一次。只在最后一次进行了两次赋值
冒泡的思想是,一次比较,如果顺序反了,咱俩就换换
插入的思想是,前面的都是有序的。一次比较,如果没找到我想要的位置,那你们就往后挪个位置,腾个地方。
实现之
package sort;
import java.util.Arrays;
public class ShellInsertSort
{
public static void main(String[] args)
{
int[] arr =
{ 5, 3, 1, 2, 6, 4, 8 ,9,10,6,15,3,7};
shellInsertSort(arr);
System.out.println(Arrays.toString(arr));
}
/**
*
* @param arr
*/
public static void shellInsertSort(int[] arr)
{
for (int increment = arr.length / 2; increment > 0; increment /= 2)
{
for (int i = increment; i < arr.length; i++)
{
int temp;
int j;
// 如果这个是逆序的,那么往前找吧
if (arr[i] < arr[i - increment])
{
temp = arr[i];// 拿出这个值
// 往前找
for (j = i - increment; j >= 0 && arr[j] >= temp; j -= increment)
{
arr[j + increment] = arr[j];
}
arr[j + increment] = temp;// 找到了赋值
}
}
}
}
}