希尔排序是怎么来的?
我们此前学习了插入排序,发现他交换数据的次数仍然很多,想要降低他的次数需要将数列变得部分有序,我们可以将原来的数列分为多组,每组都进行一次插入排序,这样总体的数列就是部分有序的了。最后再将已经部分有序的数列最后进行一次插入排序时可以降低它的交换次数。
- 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率;
- 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位;
如何实现
希尔排序是把序列按下标的一定增量分组,对每组使用直接插入排序算法排序。随着增量的逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个序列恰好被分为一组(也就是最后进行一次直接插入排序),算法便终止。它每一趟的操作并没有像冒泡,选择排序一样直接对某一个数进行归位。它是在将整个数列变得部分有序,最后进行一次插入排序。
基本思想
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。
基本过程
首先,希尔排序算法效率增量序列的取值有关。这是一个很复杂的数学问题,同样,对于不同的数据,采用不同的增量也会导致算法效率的不同,这一问题还没有有效的解决。
- 我们在取增量时一般采用len/2。缩小增量为inc/2的形式。
- 外层循环:缩小增量。即控制从较少的元素分为一组插入排序到较多的元素一组插入排序。
- 里层循环:插入排序。把增量为Inc的一组数进行插入排序。当arr[i+Inc]<arr[i]时就对调两个元素下标
时间复杂度
- 最优时间复杂度:O(n ^ (1.3) )
- 最差时间复杂度:O(n ^ 2)
- 稳定性:不稳定
代码实现
Python
import numpy as np
# 请把希尔排序算法补充完整
def shellSort(arr):
inc =len(arr)//2
while inc>=1:
for i in range (0,len(arr)-inc):
while i >=0:
if arr[i+inc]<arr[i]:
arr[i+inc],arr[i]=arr[i],arr[i+inc]
i-=inc
else: break
inc //= 2
return arr
if __name__ == '__main__':
nums = np.random.permutation(20)
shellSort(nums)
print(nums)
java
import java.util.LinkedList;
class shell_sort {
int[] datas;//待排序数据
public shell_sort(int[] datas) {
this.datas = datas;
}
public void sort() {
int temp;//temp用来保存交换的数
int inc=this.datas.length/2;//排序增量
while (inc>=1){//inc 等于1时是最后一次直接插入排序
for(int i=0;i< this.datas.length-inc;i++){
while (i>=0){
if (this.datas[i+inc]<this.datas[i]){
temp=this.datas[i];
this.datas[i]=this.datas[i+inc];
this.datas[i+inc]=temp;
i-=inc;
}
else break;
}
}
inc=inc/2;
}
}
public void print(){
LinkedList list =new LinkedList();
for(int i=0;i< datas.length;i++){
list.add(datas[i]);
}
System.out.println(list);
}
public static class SortTest{
public static void main(String[] args) {
test_shellsort();
}
public static void test_shellsort(){
int[] arrays={9,1,5,8,3,7,4,6,2,0};//待排序数组
shell_sort shellSort = new shell_sort(arrays);
shellSort.sort();
shellSort.print();
}
}
}