排序算法(2)

5.希尔排序(Shell)

void shellsort1(int num[], const int len)
{
    if (len <= 1) return;

    int i, j, k, dlen, temp;

    for (dlen = len / 2; dlen > 0; dlen /= 2) //确定步长
    {
        for (i = 0; i < dlen; i++)
        {
            for (j = i + dlen; j < len; j += dlen)
            {
                temp = num[j];
                k = j - dlen;
                while (k >= 0 && num[k] > temp)
                {
                    num[k + dlen] = num[k];
                    k -= dlen;
                }
                num[k + dlen] = temp;
            }
        }
    }
}

void shellsort2(int num[], const int len)
{
    int i, j, dlen, temp;

    for (dlen = len / 2; dlen > 0; dlen /= 2)
    {
        for ( i = dlen; i < len; i++) //从第二序列开始,前面为有序区
        {
            if (num[i] < num[i - dlen])
            {
                temp = num[i];
                j = i - dlen;
                while (j >= 0 && num[j] > temp)
                {
                    num[j + dlen] = num[j];
                    j -= dlen;
                }
                num[j + dlen] = temp;
            }
        }
    }
}

一行两种写法都可以,但是后者比较便于理解和书写。

希尔排序时间复杂度为O(nlogn),不过无需额外开辟空间,属于不稳定排序。

希尔排序的时间性能优于直接插入排序,原因如下:

(1)当文件初态基本有序时,直接插入排序所需的比较和移动次数较多;

(2)当n值较小时,n和n^2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度O(n^2)差别不大。

基于以上两点,在希尔排序开始时增量较大,分组比较多,每组的记录数目较少,故各组内直接插入排序较快。后来增量逐渐缩小,分组数目逐渐较少,各组记录数目逐渐增多,但由于文件基本接近有序状态,所以新的排序过程较快。

6.快速排序(QuickSort)

//快速排序
template<typename T>
void SWAP(T& a, T&b)
{
    T temp = a;
    a = b;
    b = temp;
}

int Partition(int data[], int left, int right)
{
    if (data == NULL || left < 0 || (right - left) <= 0)
    {
        assert(false);
    }

    int pivot = data[left]; //轴心元素
    while (left < right)
    {
        //末尾元素大于轴心元素数值时,不作处理,尾指针往前递进
        while (left < right&&data[right] >= pivot)
            --right;

        //找到第一个不满足data[right]>pivot的元素,让其与data[left]交换
        SWAP(data[left], data[right]);

        //当前端的元素小于轴心元素时,不作处理,头指针往后递进
        while (left < right&&data[left] <= pivot)
            ++left;

        //找到第一个不满足data[left]<pivot的元素,让其与data[right]交换
        SWAP(data[left], data[right]);
    }

    /*由于前面
    while(start<end&&arry[end]>=pivot)和while(start<end&&arry[start]<=pivot)的限定,
    保证了最后不会出现low>high的情况,因此最后low=high,该位置就是轴心元素在数组中的置。
    */
    return left;
}

void Qsort(int data[], int left, int right)
{
    if (left < right)
    {
        //此步保证data[pivot]大于左边的元素小于右边的元素,arry[pivot]被正确安排
        int pivot = Partition(data, left, right);
        Qsort(data, left, pivot - 1);
        Qsort(data, pivot + 1, right);
    }
}

void QuickSort(int data[], const int& length)
{
    if (data == NULL || length <= 1)
        return;

    Qsort(data, 0, length - 1);
}

很好玩的算法,理解确实要花一点时间。

具体原理解释可以参考:http://blog.csdn.net/morewindows/article/details/6684558,结合里面的图解,学习曲线一下就降下来了。

7.二分查找(随机乱入)

//二分查找
int binary_search(int data[], const int length, const int target)
{
    if (data == NULL || length <= 0)
        return -1;

    int left = 0, right = length - 1, mid = 0;

    while (left <= right)
    {
        mid = (left + right) >> 1;
        if (data[mid] == target)
        {
            return mid;
        }
        else if (data[mid] < target)
        {
            right = mid - 1;
        }
        else if (data[mid] > target)
        {
            left = mid + 1;
        }
    }

    return -1;
}

剑指offer中有一个寻找旋转数组中最小值,二分查找的变形,蛮不错的。

原文地址:https://www.cnblogs.com/jason1990/p/4679370.html