排序算法

2018-12-02  本文已影响0人  szn好色仙人

插入排序

//升序
template<typename T>
void InsertSort(T* pValue, const size_t nLenC)
{
    for (size_t i = 1; i < nLenC; ++i)
    {
        auto nTem = pValue[i];
        auto nId = i - 1;

        while (nId >= 0 && pValue[nId] > nTem)
        {
            pValue[nId + 1] = pValue[nId];
            --nId;
        }

        pValue[nId + 1] = nTem;
    }
}

分治排序

template<typename T>
void Merge(T* pLeft, const size_t nLeftSizeC, T* pRight, 
    const size_t nRightSizeC, T* pOut)
{
    size_t i = 0;       //左边buff的id
    size_t j = 0;       //右边buff的id
    size_t k = 0;       //输出buff的id

    while (i < nLeftSizeC || j < nRightSizeC)
    {
        if (i < nLeftSizeC && j < nRightSizeC)
        {
            if (pLeft[i] > pRight[j])
            {
                goto LeftBig;
            }
            else
            {
                goto RightBig;
            }
        }
        else if (i == nLeftSizeC)
        {
            goto LeftBig;
        }
        else
        {
            goto RightBig;
        }

    LeftBig:
        pOut[k++] = pRight[j++];
        continue;

    RightBig:
        pOut[k++] = pLeft[i++];
    }
}

template<typename T>
void MergeSort(T* pBuff, const size_t nSizeC)
{
    auto nLeft = nSizeC / 2;
    auto nRight = nSizeC - nLeft;

    if (nLeft > 1)
    {
        MergeSort(pBuff, nLeft);
    }

    if (nRight > 1)
    {
        MergeSort(pBuff + nLeft, nRight);
    }

    T* pOut = new T[nSizeC];
    Merge(pBuff, nLeft, pBuff + nLeft, nRight, pOut);
    memcpy(pBuff, pOut, sizeof(T) * nSizeC);
    delete[] pOut;
}

堆排序

//获取当前节点的左子节点
int GetLeft(const int nIdC)
{
    return 2 * (nIdC + 1) - 1;
}

//获取当前节点的右子节点
int GetRight(const int nIdC)
{
    return 2 * (nIdC + 1);
}

/*
假定Left(nIdC)和Right(nIdC)所构成的二叉树都是最大堆,则nIdC可能
不满足最大堆的性质,利用此函数,将nIdC所代表的元素下沉到合适位置,
则维护了最大堆的性质

此函数复杂度:O(lgn)
*/
template<typename T>
void MaxHeap(T* pBuff, const int nIdC, const int nSizeC)
{
    auto nLeft = GetLeft(nIdC);
    auto nRight = GetRight(nIdC);
    auto nBigId = nIdC;

    if (nLeft < nSizeC && pBuff[nLeft] > pBuff[nBigId])
    {
        nBigId = nLeft;
    }

    if (nRight < nSizeC && pBuff[nRight] > pBuff[nBigId])
    {
        nBigId = nRight;
    }

    if (nBigId != nIdC)
    {
        std::swap(pBuff[nIdC], pBuff[nBigId]);
        MaxHeap(pBuff, nBigId, nSizeC);
    }
}

/*
利用自底向上的方法,利用 MaxHeap 将输入数组构建为最大堆

此函数复杂度为O(n),此处证明见算法导论
*/
template<typename T>
void BuildHeap(T* pBuff, const int nSizeC)
{
    for (int i = nSizeC / 2; i >= 0; --i)
    {
        MaxHeap(pBuff, i, nSizeC);
    }
}

/*
不断构建最大堆且取其根节点的过程
*/
template<typename T>
void HeapSort(T* pBuff, const int nSizeC)
{
    BuildHeap(pBuff, nSizeC);
    for (int i = nSizeC - 1; i >= 1; --i)
    {
        std::swap(pBuff[0], pBuff[i]);
        BuildHeap(pBuff, i);
    }
}

快排

template<typename T>
size_t Partition(T* pBuff, const size_t nSizeC)
{
    //增加算法的随机性
    srand(static_cast<unsigned int>(time(0)));
    std::swap(pBuff[nSizeC - 1], pBuff[rand() % nSizeC]);

    T nValue = pBuff[nSizeC - 1];
    size_t nPos = 0;

    for (size_t i = 0; i < nSizeC - 1; ++i)
    {
        if (pBuff[i] < nValue)
        {
            std::swap(pBuff[nPos], pBuff[i]);
            ++nPos;
        }
        /*
        说明:
        nPos以左的值均小于划分值,nPos以右且i以左均大于划分值
        i以右不做限制
        */
    }

    std::swap(pBuff[nPos], pBuff[nSizeC - 1]);

    return nPos;
}

template<typename T>
void QuickSort(T* pBuff, const size_t nSizeC)
{
    if (nSizeC > 1)
    {
        auto nId = Partition(pBuff, nSizeC);
        QuickSort(pBuff, nId);
        QuickSort(pBuff + nId, nSizeC - nId);
    }
}

线性时间排序

比较排序算法的下界
计数排序
template<typename T>
void CountSort(T* pArray, const int nLenC, const int nMaxValueC)
{
    //存放计数
    auto pCount = new T[nMaxValueC + 1]();
    
    //存放排序好的结果
    auto pOut = new T[nLenC]();

    for (int i = 0; i < nLenC; ++i)
    {
        //pCount[i]包含了pArray所有值为i的元素个数
        ++pCount[pArray[i]];
    }

    for (int i = 1; i < nMaxValueC + 1; ++i)
    {
        //pCount[i]中存储了pArray中所有小于等于i的值
        pCount[i] += pCount[i - 1];
    }

    for (int i = nLenC - 1; i >= 0; --i)
    {
        //根据pCount存储的值,就可以直接得到pArray[i]排序好后的位置
        pOut[pCount[pArray[i]] - 1] = pArray[i];
        --pCount[pArray[i]];
    }

    memcpy(pArray, pOut, sizeof(T) * nLenC);

    delete[] pCount;
    delete[] pOut;
}
基数排序
桶排序
上一篇下一篇

猜你喜欢

热点阅读