排序算法之插入排序2——折半插入排序

我们都知道插入法是在要插入的元素前面都已序的情况下进行比较—插入,直接插入法每个元素都有可能会经历多次交换才能找到它本应该待的位置。比如第100个元素,假如它应该待的位置为2,如果用直接插入法的话,就要比较99次,搬移98次。然而它前面的99个元素是已序的,显然有优化的空间,面对已序的序列我们最先想到的就是二分算法,我们可以先用二分法找到这个元素应该待的位置,然后一次性的将这个位置后面的元素后移,再将原来第100个元素放入这个位置,这就少了很多比较的开销。
折半插入法的比较次数与待排序序列的初始状态无关,仅与数量有关,它的比较次数为O(N*lgN),空间复杂度为O(N)而且这是一个稳定的算法。
下面是排序算法的实现:

#include "compare.hpp"
template <typename T>
static int BinaryFind(T *array, T key, int left, int right)
{
    assert(NULL != array);
    assert(left >= 0 && right >= 0 && left < right);
    if(right - left == 1 && Less<T>()(key, array[left]))
        return left;
    while(left < right)
    {
        int mid = left + ((right-left)>>1);
        if((mid == left && Less<T>()(key, array[mid]))
        || (Less<T>()(key, array[mid]) && Less<T>()(array[mid-1], key)))
            return mid;
        else if(Less<T>()(key, array[mid]))
            right = mid;
        else
            left = mid+1;
    }
    return right;
}

template <typename T>
void BinaryInsert(T *array, const int size)
{
    assert(NULL != array && size > 0);
    if(size == 1)
        return;
    for(int i = 1; i < (int)size; i++)
    {
        T temp = array[i];
        int place = BinaryFind(array, temp, 0, i);
        if(place < i)
        {
            for(int j = i; j > place; j--)
                array[j] = array[j-1];              
            array[place] = temp;
        }
    }
}

算法中用到的比较器实现:

template <typename T>
struct Less
{
    bool operator()(T &left, T &right)const
    {
        return left < right;
    }
};

template <typename T>
struct Greater
{
    bool operator()(T &left, T &right)const
    {
        return left > right;
    }
};

测试代码:

void test2()
{
    int arr[100] = { 0 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    srand((unsigned int)time(0));
    for(int i = 0; i < sz; i++)
    {
        arr[i] = rand() % sz;
    }
    for(int i = 0; i < sz; i++)
        cout << arr[i] << " ";
    cout << endl << endl << endl << "sort:" << endl;
    BinaryInsert(arr, sz);
    for(int i = 0; i < sz; i++)
        cout << arr[i] << " ";
    cout << endl;
    for(int i = 1; i < sz; i++)
    {
        if(Less<int>()(arr[i], arr[i-1]))
            cout << "insert sort error! " << i << endl;
    }
}

这里最后一个for循环是用于检测数值经过排序后是否已序,如排序失败则会打出insert sort error!字样,并输出排序出错的第一个数字。下面看排序结果:
这里写图片描述
排序结果正确。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值