数据结构排序--直接插入和希尔排序

来源:互联网 发布:铁三角ck330is知乎 编辑:程序博客网 时间:2024/04/30 05:24

正文:

直接插入排序:是将待测数与已经有序的数列从最右边开始比较,然后将数插入到合适的位置,完成排序。

在这里面提到了待测数和已经有序数列。  

已经有序序列:顾名思义,存放的元素已经按照从小到大或者从大到小排列完毕

带测数:紧挨有序序列的第一个数。

在直接插入排序中,第一躺插入默认的是第一个元素为第一个有序序列,将带测数放入tmp中,和已经有序序列的最右边的数进行比较,找到合适的位置插入。以下用图形来表示,红框代表已经有序序列,绿框代表待测数。




12比33小因此不插入不动,那么继续




64比12大,那么12向后移动一个格子,这时12会占用到原来带测数的格子,但并没有关系,因为64放在了tmp中,64又比33大,因此33再向后移动一个格子,这时第一个格子空了下来,并且有序序列已经比较完毕,把64插入到第一个格子中。



依次下去,完成排序

以下是代码实现:

void Sort(int *arr, int len)      //直接插入排序, 时间复杂度O(2^n)   空间复杂度O(1)   稳定排序{int i;int j;for (i = 1; i < len; i++)       //第一个数默认为第一个有序序列,因此从第二个开始{int tmp = arr[i];              //待测数for (j = i - 1; j >= 0 && arr[j] < tmp; j--)    //待测数的前面一个数就是有序数列最右边的数。{arr[j + 1] = arr[j];              //比该数小的向后推位}arr[j + 1] = tmp;    //因为循环是J--因此在这里要+1.}}


希尔排序:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插
入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的。

一般我们在分割子序列是以5,3,1来分割。

先是按照5来分割子序列:


不同颜色代表的就是按照5来分割出来的子序列,那么就是相当于是33和99一组,21和3一组,83和9一组。然后进行我们的直接插入排序。

99比33大插入,3比21小不动,9比83小不动。那么得到的结果就是:

99,21,83,7,18,33,3,9       序列就会变得较有序。

然后进行我们的按照3来分割


还是一样不同的颜色代表的是按照3分割出来的序列。然后分别每个序列进行直接插入排序

然后得到的结果:99,21,83,7,18,33,3,9     按照排序发现没有任何改动(说明我举得例子不太好,但是无所谓,要知道他是按照直接插入排序排过的,只是巧合性的看起来没发生变化)。   

最终我们按照 1来分割,其实就是我们进行完整的一次直接插入排序,这里我就不写过程了(上面有)。最终完成我们的排序。

而我们按照5,3,1来分,我们可以把这个分割的dk值也创建一个数组放入,所以我们就可以在主函数中给调用函数传入我们想要分割的规则。

接下来就是代码的实现:

void Shell(int *arr, int len, int dk)  //希尔排序   时间复杂度O(n^1.3)   空间复杂度O(1)    不稳定{int i;int j;for (i = dk; i < len; i++)    {int tmp = arr[i];for (j = i - dk; j >= 0 && arr[j] < tmp; j = j - dk){arr[j + dk] = arr[j];}arr[j + dk] = tmp;}}void Sort(int *arr, int arr_len, int *brr,int brr_len)          //brr中放的就是我们的分割规则  5,3,1   {int i;for (i = 0; i < brr_len; i++){Shell(arr, arr_len, brr[i]);        //划分好dk然后用直接插入排序来排}}


原创粉丝点击