直接插入排序和希尔排序的实现

OK,要完成一个排序,第一步是画图并写出第一堂排序。

 OK,上面有一个有序数组,现在我要分别将 1和3分别插入到这个数组;以第一组为例,我定义了一个end,将 1和a[end]进行比较,如果a[end]大,则向后移一位,并且end--,a[end]小或者相等,则插入a[3],最后如下图所示

 此时end为 -1,我们将它插入到a[0]位置中,即a[end+1]的位置中;

第二种情况最后结束的标志是

 此时 3 要插入的位置依旧为 a[end+1] ,所以,综上两种情况,这个数据要插入的位置为a[end+1];

代码如下:

void InsertSort(int* a,int n)
{
    //在此以升序为主

    //注意,这是一趟的排序   且要求这个数组必须是有序的
    
    int end;   //最后一个位置
    int tmp = a[end+1];   //要插入的数据,先保存起来

    while(end>=0)   //因为end的极限为 -1

    {
        if(a[end] > tmp)
        {
            a[end+1] = a[end]  //后移一位
            end--;
        }
        
        else
        {
            break;  //找到了插入位置
        }
    }

    a[end + 1]  = tmp;  //两种情况,要么end = -1,要么 a[end] < tmp;
}

OK,第一趟排序我们已经完成了,上面有个条件,即要求被插入的这个数组需要时有序的。

那么如何确保是有序的呢? 相信你已经知道了,从数组的第一个元素开始不久OK了吗?每个元素对于他自身来说都是有序的,So,代码如下:

void InserSort(int *a,int n)
{
    assert(a);
    int i = 0;
    
    for(i = 0;i < n-1;i++)
    {
        int end = i;  //从第一个元素开始排;
        int tmp = a[end + 1];
        while(end >= 0)        
        {
            if(a[end] > tmp)
            {
                a[end + 1] = a[end];
                end--;
            }
            
            else
            {
                break;
            }
        }
        a[end + 1] = tmp;
    }
}

那么插入排序的时间复杂度是:O(N^2);

空间复杂度为 O(1);

如果插排在 顺序有序或者接近有序的条件下的时间复杂度会达到O(N),所以插排还是有价值的.

 直接插入排序的稳定性:不稳定;

希尔排序  --- 可以认为是 直接插入排序的 优化,是一个很强的排序。

它分为  多次预排序(gap > 1)直接插入排序(gap == 1)

同上,首先我们应该写入他的第一趟排序 :

 

void ShellSort(int *a,int n)
{
    int gap = 3;
    int end = 0;
    int tmp = a[end + gap]

    while(end >= 0)        

    {
        if(a[end]>tmp)
        {
            a[end + gap] = a[end];   
            end -= gap;
        }
        else
        {
            break;
        }
    }
    
    a[end + gap] = tmp;
}

 上面的代码已经排了其中一趟中的一个数据,那么如何控制图中红色的那一趟数据呢?OK

是不是只要加一个变量I ,I += gap 进行遍历就可以了,代码如下
 

void ShellSort(int *a,int n)
{

    int i = 0;
    int gap = 3;
    for(i = 0;i < n - gap;i+=gap)
    {
        int end = i;
        int tmp = a[end + gap]

        while(end >= 0)        

        {
            if(a[end]>tmp)
            {
                a[end + gap] = a[end];   
                end -= gap;
            }
            else
            {
                break;
            }
        }
    }
    
        a[end + gap] = tmp;
}

上述代码已经将其中的一趟排序(红色那一趟)好了,那如何控制gap趟呢?OK,再用一个变量就可以了,代码如下

void ShellSort(int *a,int n)
{
    int gap = 3;
    int j = 0;
    for(j = 0;j < gap;j++)
    {
        int i = j;
    
        for(i = j;i < n - gap;i+=gap)
        {
            int end = i;
            int tmp = a[end + gap]

            while(end >= 0)        

            {
                if(a[end]>tmp)
                {
                    a[end + gap] = a[end];   
                    end -= gap;
                }
                else
                {
                    break;
                }
            }
        }
    
            a[end + gap] = tmp;
    }
}

当然还有一种方式,就是一锅炖,不分几趟,挨个挨个的来,OK代码如下

void ShellSort(int *a,int n)
{
    int gap = 3;

    for(i = 0;i < n - gap;i++)
    {
        int end = i;
        int tmp = a[end + gap]

        while(end >= 0)        

        {
            if(a[end]>tmp)
            {
                a[end + gap] = a[end];   
                end -= gap;
            }
            else
            {
                break;
            }
        }
    }
    
        a[end + gap] = tmp;   
}

此时就完成了希尔排序的预排序,但其中也有一些我们需要知道的,例如,我们这个预排序的

时间复杂度是多少:最好 O(N),最坏呢: F(N + gap) = (1+2+3+...+N/gap)*gap;

gap越大,预排越快,预排后越不接近有序;

gap越小,预排越慢,预排后越接近有序

不难发现,当gap 为 1时 这就是个直接插入排序 时间复杂度为 O(N^2),

OK现在既然预排序处理完了,那么接下来如何控制多组预排序和直接插入排序呢?

很简单,控制gap不久OK了吗?当gap>1时 多组预排,gap == 1时为直接插入排序

代码如下:
 

void ShellSort(int *a,int n)
{
    int gap = n

    while(gap > 1)
    {
        gap /= 2;
        //gap = gap / 3 + 1 //确保最后一次为直接插入排序        

        for(i = 0;i < n - gap;i++)
        {
            int end = i;
            int tmp = a[end + gap]

            while(end >= 0)        

            {
                if(a[end]>tmp)
                {
                    a[end + gap] = a[end];   
                    end -= gap;
                }
                else
                {
                    break;
                }
            }
        }
    
        a[end + gap] = tmp;   
    }
}

那么希尔排序的时间复杂度是多少呢 ?

希尔排序时间复杂度为:O(N*logN);

参考了一些资料,如《数据结构(C语言班)》--严蔚敏 

 希尔排序平均时间复杂度为  :  O(N^1.3);

 希尔排序的稳定性:不稳定;

最后通过一组实验数据来证明一下二者的差距:

 

 上述时间单位为ms,由此可见希尔排序对直接插入排序的优化是显而易见的。

  • 11
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值