直接插入排序和希尔排序

来源:互联网 发布:证件照片制作软件app 编辑:程序博客网 时间:2024/04/30 07:46

直接插入排基本思想:顺序地把待排序的数据元素按关键值的大小插入到已排序数据元素的子集合的适当位置。

从第二个元素开始,不断地将新添加的元素插入到原来已排序的子集合中去,直到所有元素有序。

以升序为例:

//***********1直接插入排序*************************void InsertSort(int a[],int len){int i,j,key;for(i=1;i<len;i++){key=a[i];//关键值j=i-1;while(j>=0 && a[j]>key)//比key大的所有元素右移赋值{a[j+1]=a[j];j--;}a[j+1]=key;//找到插入位置}}


空间复杂度:O(1)
时间复杂度:最好情况,升序有序,比较n-1次,后移0次----->O(n)

                        最坏情况,逆序,比较n(n-1)/2,后移n-1次----->O(n^2)

稳定性分析:插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。当然,刚开始这个有序的小序列只有1个元素,就是第一个元素。比较是从有序序列的末尾开 始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。如果碰见一个和插入元素相 等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳 定的。

每次插入的过程中,总是从后往前依次寻找插入位置。可以用二分查找的方式优化。

//***********1.1二分插入排序*************************//在直接插入排序基础上,查找插入位置时使用二分查找的方式void BinInsertSort(int a[],int len){int i,j,key,left,right,mid;for(i=1;i<len;i++){key=a[i];left=0;right=i-1;while(left<=right){mid = (left+right)/2;if(a[mid]>key)right = mid-1;elseleft = mid+1;}for(j=i-1;j>=left;j--)a[j+1] = a[j];a[left] = key;}}
最好情况:查找的位置是有序区最后一位的后面一位,即插入新元素时无需后移,比较次数log2(n)---->时间复杂度O(log2(n))

最坏情况:查找的位置时有序区第一位 比较log2(n)  赋值n(n-1)/2+n-1---->时间复杂度O(n^2)

直接插入排序的效率在某些情况下很高,如1,:记录基本有序,只需要少量插入操作就可以完成排序。2:记录数较少。

为了改进直接插入排序,不满足条件就要尽可能的创造这两个条件。

主要的改进思想如下:1:将待排的元素分组,对各子序列分别进行直接插入排序,当整个序列基本有序时,再来一一次直接插入排序。2为了保证各子序列排序后,各子序列组成的整个序列基本有序,而不是局部有序,采用跳跃分割。(增量)

例如:对于待排元素 {9 1 5 8 3 7 4 6 2}

分组,第一种分割 { 9 1 5}{8 3 7}{4 6 2}子序列排序{1 5 9}{3 7 8}{2 4 6}------>{1 5 9 3 7 8 2 4 6}。不是基本有序,而是局部有序

   第二种分割跳跃分割,增量为3   分组为{9 8 4}{1 3 6}{5 7 2}子序列排序后{4 8 9}{1 3 6}{2 5 7}-------->{4 1 2 8 3 5 9 6 7} 基本有序,每个子序列的最小元素都放在

  原序列的前面,较大的都放在中间,最大的部分放在最后,这样保证基本有序

希尔排序的基本思想是先将整个待排序元素分割成若干子序列分别进行排序,待整个序列中的元素基本有序时,再对全体元素进行一次直接插入排序。

                希尔排序又叫缩小增量排序,分组直接插入排序

//***********2希尔排序***"缩小增量排序"****************void  ShellSort(int a[],int len){    int i,j,temp;    int interval=len/2;//初始增量    while(interval!=0)    {    for (i=interval;i<len;i++)    {    j=i-interval;    while(j>=0 && a[j]>a[j+interval])    {    temp = a[j+interval];    a[j+interval]=a[j];    a[j]=temp;    j=j-interval;    }    }    interval=interval/2;//interval=1时为直接增量排序    }}

时间复杂度分析:

最好:序列升序,比较n-1次 移动赋值0次 ------>O(n)

最坏:O(nlog2(n)) 

平均:O(nlog2(n))

希尔排序时间复杂度与增量有关,平均时间复杂度和最坏情况差不多。

稳定性分析:希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小, 插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比o(n^2)好一些。由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元 素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。

改进:1二分查找位置

    2

for (i=interval;i<len;i++)//for (i=interval;i<len;i=i+interval)

参考:《大话数据结构》

0 0
原创粉丝点击