汉诺塔采用的是一个经典递归算法,以前我在学《数据结构》时涉及过,前不久公司组织拓展活动,活动期间有一项就是移动汉诺塔,因此活动结束后我重新设计并实现了这一算法。其中和书中讲的略有区别,但大同小异,以记后来。
1 头文件声明
// 一个汉诺塔
struct stOneHLT{
stOneHLT()
{
HLTName = "";
SourceNums = 0;
Numslist.clear();
//pUpHLT = NULL;
}
stOneHLT(const stOneHLT& otherOneHLT)
{
if (this != &otherOneHLT)
{
Numslist.clear();
list<int>::const_iterator it = otherOneHLT.Numslist.begin();
while (it != otherOneHLT.Numslist.cend())
{
Numslist.push_back(*it);
it++;
}
HLTName = otherOneHLT.HLTName;
SourceNums = otherOneHLT.SourceNums;
}
}
stOneHLT operator = (const stOneHLT& otherOneHLT)
{
if (this != &otherOneHLT)
{
Numslist.clear();
list<int>::const_iterator it = otherOneHLT.Numslist.begin();
while (it != otherOneHLT.Numslist.cend())
{
Numslist.push_back(*it);
it++;
}
HLTName = otherOneHLT.HLTName;
SourceNums = otherOneHLT.SourceNums;
}
return *this;
}
CString HLTName; // 汉诺塔名
int SourceNums; // 原始所有层级
list<int> Numslist; // 当前塔的所有盘子
//stOneHLT* pUpHLT;
};
// 汉诺塔
class CHLT{
public:
CHLT(int cj,CListBox* pListBox);
protected:
// 判断移动方向,moveLeve:为待移动的层级
stOneHLT& CheckMoveDirection(int moveLeve, stOneHLT& sourceOneHLT, stOneHLT& tmpOneHLT, stOneHLT& TargetOneHLT);
void Move4(stOneHLT& sourceOneHLT, stOneHLT& tmpOneHLT, stOneHLT& TargetOneHLT, int movenum);
stOneHLT& FindHLT(int findValue, stOneHLT& sourceOneHLT, stOneHLT& tmpOneHLT, stOneHLT& TargetOneHLT);
void showMove(int i, stOneHLT& sourceOneHLT, stOneHLT& TargetOneHLT);
public:
void beginMove();
private:
stOneHLT AOneHLT; // A汉诺塔
stOneHLT BOneHLT; // B汉诺塔
stOneHLT COneHLT; // C汉诺塔
int m_MoveNums; // 移动的次数
stOneHLT* PrevHLT;
CListBox* m_pListBox; //
};
2 实现文件
//----------------------------------CHLT begin------------------------------------------------------
CHLT::CHLT(int cj,CListBox* pListBox)
{
AOneHLT.HLTName = _T("A");
BOneHLT.HLTName = _T("B");
COneHLT.HLTName = _T("C");
m_pListBox = pListBox;
for (int i = 0; i < cj; i++)
{
AOneHLT.Numslist.push_back(i + 1);
}
AOneHLT.SourceNums = AOneHLT.Numslist.size();
BOneHLT.Numslist.clear();
COneHLT.Numslist.clear();
PrevHLT = NULL;
m_MoveNums = 0;
}
stOneHLT& CHLT::FindHLT(int findValue, stOneHLT& sourceOneHLT, stOneHLT& tmpOneHLT, stOneHLT& TargetOneHLT)
{
list<int>::iterator it = sourceOneHLT.Numslist.begin();
while ( it != sourceOneHLT.Numslist.end() )
{
if (findValue == *it)
{
return sourceOneHLT;
}
it++;
}
it = tmpOneHLT.Numslist.begin();
while (it != tmpOneHLT.Numslist.end())
{
if (findValue == *it)
{
return tmpOneHLT;
}
it++;
}
it = TargetOneHLT.Numslist.begin();
while (it != TargetOneHLT.Numslist.end())
{
if (findValue == *it)
{
return TargetOneHLT;
}
it++;
}
}
void CHLT::showMove(int i, stOneHLT& sourceOneHLT, stOneHLT& TargetOneHLT)
{
m_MoveNums++;
CString msg;
msg.Format(_T("%d %s->%s"), i, sourceOneHLT.HLTName.GetBuffer(), TargetOneHLT.HLTName.GetBuffer());
sourceOneHLT.HLTName.ReleaseBuffer();
TargetOneHLT.HLTName.ReleaseBuffer();
CString tmp = msg;
//msg.Format(_T("第%d层"), i, sourceOneHLT.HLTName.GetBuffer(), TargetOneHLT.HLTName.GetBuffer());
OutputDebugString(msg.GetBuffer());
if (m_pListBox)
{
m_pListBox->AddString((LPCTSTR)tmp.GetBuffer());
tmp.ReleaseBuffer();
}
}
void CHLT::Move4(stOneHLT& sourceOneHLT, stOneHLT& tmpOneHLT, stOneHLT& TargetOneHLT, int movenum)
{
for (int i = 1; i <= movenum; i++)
{
sourceOneHLT.SourceNums = movenum;
stOneHLT& FindMovedHLT = CheckMoveDirection(i, sourceOneHLT, tmpOneHLT, TargetOneHLT);
if (FindMovedHLT.Numslist.size() == 0 || i < FindMovedHLT.Numslist.front())
{
sourceOneHLT.Numslist.pop_front();
FindMovedHLT.Numslist.push_front(i);
showMove(i, sourceOneHLT, FindMovedHLT);
if (i != 1)
{
stOneHLT& upHLT = FindHLT(i - 1, sourceOneHLT, tmpOneHLT, TargetOneHLT);
if (sourceOneHLT.HLTName.Compare(upHLT.HLTName.GetBuffer()) != 0 && sourceOneHLT.HLTName.Compare(FindMovedHLT.HLTName.GetBuffer()) != 0)
Move4(upHLT, sourceOneHLT, FindMovedHLT, i - 1); // 将辅助塔上面的当前目标塔
else
if (tmpOneHLT.HLTName.Compare(upHLT.HLTName.GetBuffer()) != 0 && tmpOneHLT.HLTName.Compare(FindMovedHLT.HLTName.GetBuffer()) != 0)
Move4(upHLT, tmpOneHLT, FindMovedHLT, i - 1); // 将辅助塔上面的移到当前目标塔
else
Move4(upHLT, TargetOneHLT, FindMovedHLT, i - 1); // 将辅助塔上面的移到当前目标塔
}
}
}
}
stOneHLT& CHLT::CheckMoveDirection(int moveLeve, stOneHLT& sourceOneHLT, stOneHLT& tmpOneHLT, stOneHLT& TargetOneHLT)
{
int nNums = sourceOneHLT.SourceNums;
if (nNums % 2 == 0) // 总数为双数
{
if (moveLeve % 2 == 0) //
return TargetOneHLT; // 双数层 移动到目标层
else
return tmpOneHLT; // 单数层移动到中间层
}
else // 总数为单数
{
if (moveLeve % 2 == 0) //
return tmpOneHLT; // 双数层移动到中间层
else
return TargetOneHLT; // 单数层移动到目标层
}
}
void CHLT::beginMove()
{
#if 0
Move(AOneHLT, BOneHLT, COneHLT, AOneHLT.Numslist.size());
#else
Move4(AOneHLT, BOneHLT, COneHLT, AOneHLT.Numslist.size());
#endif
//char msg[100] = { 0 };
//CListBox* pListbox = (CListBox*)GetDlgItem(IDC_LIST1);
CString msg;
msg.Format(_T("移动的总次数:%d"), m_MoveNums);
//sprintf_s(msg, 100, "移动的总次数:%d\n", m_MoveNums);
//OutputDebugString(msg.GetBuffer());
if (m_pListBox)
{
m_pListBox->AddString(msg.GetBuffer());
int nCount = m_pListBox->GetCount();
if (nCount > 0)
m_pListBox->SetCurSel(nCount - 1);
}
}
//----------------------------------CHLT end------------------------------------------------------
3 调用程序
在mfc的界面上放入一个按钮,在此按钮的单击事件中实现如下代码:
void CHLTDlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
for (int i = m_pBox->GetCount() - 1; i >= 0; i--)
{
m_pBox->DeleteString(i);
}
CHLT HLT(m_nCJ, m_pBox/*pListbox*/);
HLT.beginMove();
}