《编程之美》之一摞烙饼的排序

星期五的晚上,一帮同事在希格玛大厦附近的“硬盘酒吧”多喝了几杯,程序员多喝了几杯之后谈什么呢?自然是算法

问题。有个同事说:

“我以前在餐厅打工,顾客经常点非常多的烙饼。店里的烙饼大小不一,我习惯在到达顾客饭桌前,把一摞饼按照大小

次序摆好---小的在上面,大的在下面。由于我一只手托着盘子,只好用另一只手,一次抓住最上面的几块饼,把它们

上下颠倒个个儿,反复几次之后,这摞烙饼就排好序了。我后来想,这实际上是个有趣的排序问题:假设有n块大小

不一的摞饼,那最少要翻几次,才能达到大小有序的结果呢?”

从这段描述中我们可以很容易的就把问题抽象出来:给你一个由 n 个连续整数组成的数组,数组是无序的,现在要你

对这个数组进行升序排序,但只能对数组进行一种操作,就是只能对从数组第一个元素开始到数组中任意一个元素之

间的所有元素进行翻转。只是这样的话,问题还不是很麻烦。这里还要求我们写程序输出最优的翻转过程。

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

class CPrefixSorting
{
public:
	int * m_SwapArray;
	int * m_SwapTempArray;
	int * m_PieTempArray;
	int m_nPieCount;
	int * m_PieArray;
	int m_nMaxSwapCount;

public:
	CPrefixSorting()
	{
	}

	virtual ~CPrefixSorting()
	{
	}

public:
	void OutPut()
	{
		for (int i = 0; i < m_nMaxSwapCount; i++)
		{
			printf("%d\n", m_SwapArray[i]);
		}
	}

	/*遍历搜寻所有解法*/
	bool Search(int nStep)
	{
		/*剪枝:如果比最普通的解法还要差劲,干脆舍弃*/  
		int nMinTimes = LowerBound(m_PieTempArray, m_nPieCount);
		if (nStep + nMinTimes > m_nMaxSwapCount)
		{
			return false;
		}

		if (IsSorted())
		{
			/*如果找到一个更优解法,则保存这个更优的解法*/
			if (nStep < m_nMaxSwapCount)
			{
				m_nMaxSwapCount = nStep;
				for (int i = 0; i < m_nMaxSwapCount; i++)
				{
					m_SwapArray[i] = m_SwapTempArray[i];
				}
			}
			return true;
		}

		/*颠倒此次烙饼后,遍历接下来全部可能的颠倒情况*/
		for (int i = 1; i < m_nPieCount; i++)
		{
			Reverse(0, i);
			m_SwapTempArray[nStep] = i;
			Search(nStep + 1);
			Reverse(0, i);
		}
	}

	bool IsSorted()
	{
		for (int i = 0; i < m_nPieCount - 1; i++)
		{
			if (m_PieTempArray[i] > m_PieTempArray[i + 1])
			{
				return false;
			}
		}
		return true;
	}

	void Init(int* pPieArray, int nPieCount)
	{
		assert(NULL != pPieArray);
		assert(0 < nPieCount);

		m_PieArray = new int[nPieCount];
		assert(NULL != m_PieArray);
		m_PieTempArray = new int[nPieCount];
		assert(NULL != m_PieTempArray);
		m_nPieCount = nPieCount;

		for (int i = 0; i < nPieCount; i++)
		{
			m_PieArray[i] = pPieArray[i];
			m_PieTempArray[i] = pPieArray[i];
		}

		m_nMaxSwapCount = UpperBound(nPieCount);
		m_SwapArray = new int[m_nMaxSwapCount];
		assert(NULL != m_SwapArray);
		m_SwapTempArray = new int[m_nMaxSwapCount];
		assert(NULL != m_SwapTempArray);
	}

	void Reverse(int nBegin, int nEnd)
	{
		assert(nBegin < nEnd);
		int i, j, t;
		for (i = nBegin, j = nEnd; i < j; i++, j--)
		{
			t = m_PieTempArray[i];
			m_PieTempArray[i] = m_PieTempArray[j];
			m_PieTempArray[j] = t;
		}
	}

	void Run(int* pPieArray, int nPieCount)
	{
		Init(pPieArray, nPieCount);
		Search(0);
		OutPut();
	}

	int UpperBound(int nPieCount)
	{
		return (nPieCount - 1) * 2;
	}

	int LowerBound(int* pPieArray, int nPieCount)
	{
		int ret = 0, t;
		for (int i = 0; i < m_nPieCount - 1; i++)
		{
			t = pPieArray[i] - pPieArray[i+1];
			if (t == 1 || t == -1)
			{
				continue;
			}
			ret++;
		}
		return ret;
	}
};

int main()
{
	CPrefixSorting stSort;
	int pPieArray[10] = {3,4,0,1,2,6,5,8,7,9};
	stSort.Run(pPieArray, 10);
	system("pause");
	return 0;
}

  

转载于:https://www.cnblogs.com/binmaizhai/p/3818569.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值