原书中附的代码有笔误,以上为调试通过的代码。
#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;
}