用于保存汉诺塔的结构定义:
global type str_任务 from structure
integer 盘子个数
character _起点柱
character 中转柱
character 目标柱
integer 底盘序号
end type
每个汉诺塔, 都是用这个结构来保存的
用于求解的栈的类定义:
forward
global type uo_汉诺塔任务栈 from nonvisualobject
end type
end forward
global type uo_汉诺塔任务栈 from nonvisualobject autoinstantiate
end type
type variables
protectedwrite long il_栈顶
protectedwrite str_任务 i_任务栈[]
end variables
forward prototypes
public subroutine push (str_任务 a_任务)
public function boolean pop ()
public function boolean top (ref str_任务 a_任务)
public function boolean isempty ()
end prototypes
public subroutine push (str_任务 a_任务);
il_栈顶++
i_任务栈[il_栈顶]=a_任务
end subroutine
public function boolean pop ();
if il_栈顶>0 then
il_栈顶--
return true
else
return false
end if
end function
public function boolean top (ref str_任务 a_任务);
if il_栈顶>0 then
a_任务=i_任务栈[il_栈顶]
return true
else
return false
end if
end function
public function boolean isempty ();
return il_栈顶=0
end function
on uo_汉诺塔任务栈.create
call super::create
TriggerEvent( this, "constructor" )
end on
on uo_汉诺塔任务栈.destroy
TriggerEvent( this, "destructor" )
call super::destroy
end on
最后是主算法求解, 利用excel来演示栈的变化过程, 非常直观
/*
当前任务, 是指处在栈顶的汉诺塔任务
每个任务, 都有各自的起始柱, 中转柱, 目标柱
"循环取得
栈顶的当前任务
(栈顶出栈)"
如果当前任务的盘子个数=1, 把任务盘, 从任务起始柱移动到任务目标柱; 重入循环起点
如果当前任务的盘子个数>1, 就分解为3步, 反序压入任务栈; 压入完成后重入循环起点
第一步(入栈):把起始柱上的,当任务的次级塔(不含最大盘的n-1个盘子), 移动到任务的中转柱
第二步(入栈):把起始柱上的, 剩余的1个盘子(当前任务的最大盘), 移动到当前任务的目标柱
第三步(入栈):把当前任务中转柱上的次级塔(不含最大盘的n-1个盘子), 移动到当前任务的目标柱
*/
oleobject xlapp
long rtn
long cnt
string ls_filename, shorname
rtn = GetFileOpenName("选择文件", ls_filename, shorname, "xls", "xls Files (*.xls),*.xls", '' )
IF rtn = 1 THEN
else
return
end if
try
xlapp = create oleobject
rtn = xlapp.connecttonewobject("Excel.Application")
if rtn < 0 then
messagebox("提示","不能运行Excel程序,请检查是否已安装Microsoft Excel软件!")
else
xlapp.visible = true
xlapp.workbooks.open(ls_filename)
end if
str_任务 总任务, 栈顶任务, 子任务1, 子任务2, 子任务3
总任务.盘子个数=3 //用于演示,取3-5即可
总任务._起点柱='A'
总任务.中转柱='B'
总任务.目标柱='C'
总任务.底盘序号=3
uo_汉诺塔任务栈 st
st.push(总任务)
string ls_步骤
long i
//注意:xls文件中的演示栈是向下生长的
constant int 起始行=11 //向xls文件写入栈内数据的起始行号, 也就是栈底行号,
xlapp.ActiveSheet.Cells(起始行, 1).Value="1#栈层:"+string(st.i_任务栈[1].盘子个数)+"个盘子"+st.i_任务栈[1]._起点柱+"->"+st.i_任务栈[1].目标柱+"~r~n"
do
cnt++
st.top(ref 栈顶任务) //取得栈顶任务
st.pop()
if 栈顶任务.盘子个数=1 then //栈顶任务"可执行", 所以就只弹出, 不压入了
ls_步骤+=string(栈顶任务.底盘序号)+"#盘: "+栈顶任务._起点柱+"->"+栈顶任务.目标柱+" 第"+string(cnt)+"次循环,(被弹出的栈顶="+string(st.il_栈顶+1)+")"+"~r~n"
else
//via 是中转柱 from是起始柱, to是目标柱
//先压入栈顶的, 是第三步任务, n-1整堆v->t
//它会被后面的任务"盖上", 下沉
子任务3.盘子个数=栈顶任务.盘子个数 -1
子任务3._起点柱=栈顶任务.中转柱
子任务3.中转柱=栈顶任务._起点柱
子任务3.目标柱=栈顶任务.目标柱
子任务3.底盘序号=子任务3.盘子个数
st.push(子任务3)
//ls_步骤+="压入(n-1)"+string(子任务3.盘子个数)+子任务3._起点柱+"->"+子任务3.目标柱+"~r~n"
//再压入的是, 第二步任务, "最大盘子"f->t
子任务2.盘子个数=1
子任务2._起点柱=栈顶任务._起点柱
子任务2.目标柱=栈顶任务.目标柱
子任务2.底盘序号=栈顶任务.底盘序号
st.push(子任务2)
//ls_步骤+="压入当前最大盘"+子任务2._起点柱+"->"+子任务2.目标柱+"~r~n"
//最后压入的在最顶部, n-1整堆f->v
子任务1.盘子个数=栈顶任务.盘子个数 -1
子任务1._起点柱=栈顶任务._起点柱
子任务1.中转柱=栈顶任务.目标柱
子任务1.目标柱=栈顶任务.中转柱
子任务1.底盘序号=子任务1.盘子个数
st.push(子任务1)
//ls_步骤+="压入(n-1)"+string(子任务1.盘子个数)+子任务1._起点柱+"->"+子任务1.目标柱+"~r~n"
end if
for i=st.il_栈顶 to 1 step -1
xlapp.ActiveSheet.Cells(起始行 -1 +i, cnt+1).Value=string(i)+"#栈层:"+string(st.i_任务栈[i].盘子个数)+"个盘子"+st.i_任务栈[i]._起点柱+"->"+st.i_任务栈[i].目标柱+"~r~n"
next
loop while not st.isEmpty()
messagebox("",ls_步骤)
finally
xlapp.disconnectobject()
destroy xlapp
end try