《编程之美》烙饼排序算法学习

本文详细介绍了烙饼排序算法的实现过程,包括代码调试、优化策略、输出步骤及结果展示,旨在提供一种有效解决特定问题的算法解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


原书中附的代码有笔误,以上为调试通过的代码。

#include <iostream>
#include <cassert>
/*
烙饼排序实现
*/

using namespace std;

class CPrefixSorting
{
public:
    CPrefixSorting () : m_nCakeCnt (0), m_nMaxSwap (0), m_CakeArray(0), m_SwapArray (0),
        m_ReverseCakeArray(0), m_ReverseCakeArraySwap(0)
    {
    }

    ~CPrefixSorting () 
    {
        Finit ();
    }
    
    //
    // 计算烙饼翻转信息
    // @param
    // pCakeArray 存储烙饼索引数组
    // nCakeCnt 烙饼个数
    //
    void Run (int *pCakeArray, int nCakeCnt)
    {
        Init (pCakeArray, nCakeCnt);

        m_nSearch = 0;
        Search (0);
        
        Output ();

        ProcessOutput (pCakeArray, nCakeCnt, m_SwapArray, m_nMaxSwap);

        Finit ();
    }

private:

    //
    // 输出翻转步骤
    //
    void ProcessOutput (int *pCakeArray, int nCakeCnt, int *pSwapArray, int nMaxSwap)
    {
        int *CakeArray = new int[nCakeCnt];
        assert (CakeArray);
        for (int i = 0; i < nCakeCnt; ++i)
            CakeArray[i] = pCakeArray[i];


        cout << "[" << 0 << "]\t";
        for (int i = 0; i < nCakeCnt; ++i)
            cout << " " << CakeArray[i];
        cout << endl;

        for (int j = 0; j < nMaxSwap; ++j)
        {
            Revert (CakeArray, 0, pSwapArray[j]);
            cout << "[" <<pSwapArray[j] << "]\t";
            for (int i = 0; i < nCakeCnt; ++i)
                cout << " " << CakeArray[i];
            cout << endl;
        }
        
    }

    //
    // 输出烙饼具体翻转次数
    //
    void Output ()
    {
        for (int i=0; i< m_nMaxSwap; i++)
        {
            cout << m_SwapArray[i] << " ";
        }
        cout << "\n |Search Times| : " << m_nSearch << endl;
        cout << "Total Swap times = " << m_nMaxSwap << endl;
    }

    //
    // 初始化数组信息
    // @param
    // pCakeArray 存储烙饼索引数组
    // nCakeCnt 烙饼个数
    //
    void Init (int *pCakeArray, int nCakeCnt)
    {
        assert (pCakeArray != NULL);
        assert (nCakeCnt > 0);

        m_nCakeCnt = nCakeCnt;
        // 初始化烙饼数组
        m_CakeArray = new int[m_nCakeCnt];
        assert (m_CakeArray != NULL);
        for (int i = 0; i < m_nCakeCnt; i++)
            m_CakeArray[i] =  pCakeArray[i];

        // 设置最多交换次数信息
        m_nMaxSwap = UpBound(m_nCakeCnt) + 1;

        // 初始化交换结果数组
        m_SwapArray = new int[m_nMaxSwap];
        assert (m_SwapArray != NULL);

        // 初始化中间交换结果信息
        m_ReverseCakeArray = new int [m_nCakeCnt];
        for (int i = 0; i < m_nCakeCnt; ++i)
            m_ReverseCakeArray[i] = m_CakeArray[i];

        m_ReverseCakeArraySwap = new int[m_nMaxSwap];
    }

    //
    // 清理内存,释放资源
    //
    void Finit ()
    {
        if (m_CakeArray) { delete[] m_CakeArray; m_CakeArray = NULL; }
        if (m_SwapArray) { delete[] m_SwapArray; m_SwapArray == NULL; }
        if (m_ReverseCakeArray) { delete[] m_ReverseCakeArray; m_ReverseCakeArray = NULL; }
        if (m_ReverseCakeArraySwap) { delete[] m_ReverseCakeArraySwap; m_ReverseCakeArraySwap = NULL; }
    }

    //
    // 寻找当前翻转的上界
    //
    int UpBound (int nCakeCnt)
    {
        assert (nCakeCnt > 0);
        // 改进:上界改进
        if (nCakeCnt == 1)
            return 0;
        else
            return (nCakeCnt - 2) * 2 + 1;
    }

    //
    // 寻找当前翻转的下界
    //
    int LowerBound (int *pCakeArray, int nCakeCnt)
    {
        int t, ret = 0;

        // 根据当前数组的排序信息情况来判断最少需要多少次交换
        for (int i = 1; i < nCakeCnt; i++)
        {
            // 判断位置相邻的两个烙饼个数,是否为尺寸排序上相邻的
            t = pCakeArray[i] - pCakeArray[i-1];
            if ((t != 1) && (t != -1))
                ret++;
        }
        return ret;
    }

    // 排序的主函数
    void Search (int step)
    {
        int i, nEstimate;

        m_nSearch++;

        // 估计这次搜索所需的最小交换次数
        nEstimate = LowerBound (m_ReverseCakeArray, m_nCakeCnt);
        if (step + nEstimate >= m_nMaxSwap)
            return;

        // 如果已经排好序,即翻转完成,输出结果
        if (IsSorted (m_ReverseCakeArray, m_nCakeCnt))
        {
            if (step < m_nMaxSwap)
            {
                m_nMaxSwap = step;
                for (int i = 0; i < m_nMaxSwap; i++)
                    m_SwapArray[i] = m_ReverseCakeArraySwap[i];
            }
            
            return;
        }

        // 递归进行翻转
        for (int i = 1; i < m_nCakeCnt; i++)
        {
            // 改进:如果本次翻转为恢复上次翻转结果,则应去掉此次翻转
            if ((step > 0) && (i == m_ReverseCakeArraySwap[step - 1]))
                continue;

            Revert (0, i);
            m_ReverseCakeArraySwap[step] = i;
            Search(step + 1);
            Revert(0, i);
        }
    }

    //
    // true:已经排好序
    // false:未排好序
    //
    bool IsSorted (int *pCakeArray, int nCakeCnt)
    {
        for (int i = 1; i < nCakeCnt; ++i)
        {
            if (pCakeArray[i-1] > pCakeArray[i])
                return false;
        }
        return true;
    }

    void Revert (int *pCakeArray, int nBegin, int nEnd)
    {
        while (nBegin <  nEnd)
        {
            pCakeArray[nBegin] ^= pCakeArray[nEnd];
            pCakeArray[nEnd] ^= pCakeArray[nBegin];
            pCakeArray[nBegin] ^= pCakeArray[nEnd];
            nBegin ++;
            nEnd --;
        }
    }

    //
    // 翻转烙饼
    //
    void Revert (int nBegin, int nEnd)
    {
        static int index = 0;
        index++;
        assert (nEnd > nBegin);
        int i, j, t;

        // 翻转烙饼信息
        for (i = nBegin, j = nEnd; i < j; i++, j--)
        {
            t = m_ReverseCakeArray[i];
            m_ReverseCakeArray[i] = m_ReverseCakeArray[j];
            m_ReverseCakeArray[j] = t;
        }
    }
private:
    int *m_CakeArray;             // 烙饼信息数组
    int m_nCakeCnt;               // 烙饼个数
    int m_nMaxSwap;               // 最多交换次数
    int *m_SwapArray;             // 交换结果数组
    int *m_ReverseCakeArray;       // 当前翻转烙饼信息数组
    int *m_ReverseCakeArraySwap;   // 当前翻转烙饼交换结果数组
    int m_nSearch;                // 当前搜索次数信息
};

int cakesArray[] = { 1,2,4,3,5,6};
int cakesArray2[] = {8,6,4,2,9,7,5,3,1};
int _tmain(int argc, _TCHAR* argv[])
{
    CPrefixSorting prefix_sort;

    prefix_sort.Run (cakesArray, sizeof(cakesArray)/sizeof(cakesArray[0]));
    prefix_sort.Run (cakesArray2, sizeof(cakesArray2)/sizeof(cakesArray2[0]));

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值