一個MFC實現的漢諾塔程式
漢諾塔採用的是一個經典遞迴演算法,以前我在學《資料結構》時涉及過,前不久公司組織拓展活動,活動期間有一項就是移動漢諾塔,因此活動結束後我重新設計並實現了這一演算法。其中和書中講的略有區別,但大同小異,以記後來。
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();
}