排序算法
Posted 通凡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法相关的知识,希望对你有一定的参考价值。
本文介绍插入排序和希尔排序,插入排序是较为常见的排序算法,希尔排序也是基础的排序算法,废话不多说,具体来看一下两种算法。
插入排序
插入排序的基本思想是拿到下一个插入元素,在已经有序的待排数组部分找到自己的位置,然后进行数据的移动,完成该元素的排序,依次类推,直到整个待排数组有序,初始状态待排数组的有序部分仅有一个元素。代码如下:
public static void sort(int[] nums)
Arrays.nonBlank(nums);
for (int i = 1; i < nums.length; i++)
for (int j = i; j > 0; j--)
if (nums[j] < nums[j - 1])
int temp = nums[j];
nums[j] = nums[j - 1];
nums[j - 1] = temp;
上面这种方式两两数据交换,换到合适位置,每次交换多了两次赋值操作,下面是实现的标准模式:
public static void sort2(int[] nums)
Arrays.nonBlank(nums);
for (int i = 1; i < nums.length; i++)
int temp = nums[i]; // 记录插入值
int j;
for (j = i; j > 0 && temp < nums[j - 1]; j--)
nums[j] = nums[j - 1];// 寻找位置,能够减少赋值的次数
nums[j] = temp;// 找到位置,完毕
以上就是插入排序的两种实现方式,并没有改进,其时间复杂度为O(n^2),妥妥的两层循环,另外插入排序是稳定排序,存不存在一种改进的插入排序呢?答案是有的,这就是我们下面要介绍的希尔排序;
希尔排序
希尔排序是插入排序的改进版。主要改进思路是减少插入排序中数据的移动次数,设置步长,在初始数组较大时取较大步长,通常初始步长为待排数组长度1/2,此时只有两个元素比较,交换一次,此时数组为部分有序数组;之后步长依次减半直至步长为1,即为插入排序,此时数组已接近有序,所以插入元素时数据移动次数会相对较少,效率得到提高,实现代码如下:
public static void sort(int[] nums)
Arrays.nonBlank(nums);
int N = 0 + nums.length;
for (int gap = N / 2; gap > 0; gap /= 2)
for (int i = gap; i < N; i++)
insert(nums, i, gap);
private static void insert(int[] nums, int i, int gap)
int inserted = nums[i];
int j;
for (j = i - gap; j > 0 && nums[j] > inserted; j -= gap)
nums[j + gap] = nums[j];
nums[j + gap] = inserted;
既然为改进算法,那么相比较插入排序,希尔排序的到底快了多少呢?为此特意去找了资料,一般书上都说希尔排序的时间复杂度是O(n3/2),但是学过算法的都知道有最坏时间复杂度的,希尔排序的时间复杂度其实是和增列序列有关系的,即我们程序实现的步长,1,2,4,8,…这种序列就是我们程序中实现的这种,并不是很好的增量序列,使用这个增量序列的时间复杂度(最坏情形)是O(n2),Hibbard
提出了另一个增量序列1,3,7,…,2k-1(质数增量),这种序列的时间复杂度(最坏情形)为O(n1.5),这个提高就很厉害了,只是修改一个算法的一个参数;Sedgewick
提出了几种增量序列,其最坏情形运行时间为O(n1.3),其中最好的一个序列是1,5,19,41,109,…,最后这个就当是科普小知识吧,因为给你你也不一定能用,请原谅我的直接,当别人说希尔排序的最坏时间复杂度是O(n2)的时候,你也可以给他们科普一下,希尔排序的最坏时间复杂度是可以做到O(n^1.3)的。
总结
插入排序感觉是最为直观的排序方式,如果有人没有学过算法,人们最直接的排序方式就是,一个一个去找数字的位置,确定,然后再去找下一个,所以思想很简单,但是我们看到即时这样简单地排序思想,到了希尔这里,也能玩出花,所以对任何东西,尤其是简单的事物,都要心怀敬畏啊。
构成我们学习最大障碍的是已知的东西,而不是未知的东西。——贝尔纳
以上是关于排序算法的主要内容,如果未能解决你的问题,请参考以下文章