插入排序&希尔排序

来源:互联网 发布:淘宝童装店铺名 编辑:程序博客网 时间:2024/05/16 04:38

插入排序

1.直接插入

从左往右比较依次选出下一个数插入到前面有序区间里合适的位置,当第一次插入时,前面有序区间就是第一个值。


void InsertSort(int *a, size_t n){int begin = 0;int end = n - 1;while (begin<end){int i = begin;int tmp = a[i+1];while (i>=0&&a[i]>tmp){a[i + 1] = a[i];--i;}a[i + 1] = tmp;++begin;}}

时间复杂度

挪动的次数*数组长度

  • 逆序有序排序时间复杂度最坏O(n^2),每次比较都要比较和向前挪动整个有序区间所有的数。
  • 顺序有序排序时间复杂度最好O(n)。

适合接近顺序有序的区间进行排序

2.希尔排序

该方法又称缩小增量排序

  • 预排序 — 接近有序

思想

  • 把小的数据尽可能往前面排,把大的数据尽可能往后排,这样在进行最终插入排序时,后面的数就不会很小,这样挪动的次数就减小了。

方法

  • 取一个小于n的整数gap(gap又叫做步长),通过把所有距离为gap或者gap的倍数的数据放在一个组里,对每一个组进行插入排序,当每个组有序时,这整个序列就接近有序,然后减小gap,继续上面的操作,gap越小时,预排序完毕越接近有序,当gap等于1时,预排序就相当于直接插入排序。 

void ShellSort(int* a, size_t n){    //预排序    int gap = 3;    for(int i = 0;i<n-gap;i++) //从序列a的左边往右轮循的对距离为gap的这些分组进行预排序    {        int end = i;        int tmp = a[end+gap];//每次选出本组里的下一个值,并与前面的值比较并挪动后插入。        while(end>=0&&a[end]>tmp)         {               a[end+gap] = a[end];            end-=gap;           }        a[end+gap] = tmp;    }    }
  • 直接插入排序

但上面预排序完毕后还不是有序的,只有当gap为1时,排出来的序列才是有序的。

void ShellSort(int *a, size_t n){int gap = n;while (gap > 1){gap = gap / 3 + 1; ////加1,是因为如果最后gap为1或者2,那么除3就是0了,所以要加1,保证gap最小为1.int begin = 0;int end = n - gap; //因为现在是对距离gap为一组的记录进行排序while (begin<end)//轮循的把每个组的每个位置都判断一遍,一次预排序{int i = begin;int tmp = a[i + gap];while (i >= 0 && a[i] > tmp)//对一个组的某个位置向前比较,并进行直接插入{a[i + gap] = a[i];i -= gap;}a[i + gap] = tmp;++begin;}}}

时间复杂度

  • 希尔排序的时间复杂度与gap增量函数有关,大概是O(n^1.3)
  • 相比直接插入排序,顺序情况下不如直接插入,直接插入顺序情况时间复杂度是O(n);
  • 逆序情况就比插入排序更优;逆序时,直接插入每次要多动所有的有序序列,时间复杂度为O(n^2)。
  • 但希尔排序是不稳定,一次插入排序是不会改变相同元素的位置,但是多次插入排序,就会改变不同组里的相同元素的相对位置,因此希尔排序时不稳定。
原创粉丝点击