递归——汉诺塔问题

/*
暴力递归

暴力递归的过程就是尝试
1.把问题转化为规模缩小了的同类问题的子问题
2.有明确的不需要继续进行递归的条件(base case)
3.有当得到了子问题的结果之后的决策过程
4.不记录每一个子问题的解    记录则为动态规划
 */
/*
熟悉什么叫尝试
。打印n层汉诺塔从最左边移动到最右边的全部过程
。打印一个字符串的全部子序列
。打印一个字符串的全部子序列,要求不要出现重复字面值的子序列
。打印一个字符串的全部排列
。打印一个字符串的全部排列,要求不要出现重复排列
 */



/*

           |         |          |
          ---        |          |
         -----       |          |
        -------      |          |
          左         中         右
                   主视图


   小压大的次序将左侧柱子上的盘子移动的右侧的柱子上去,可以借助中间的柱子


                  O     O
                     O
                   俯视图

   1. 1 ~ N-1   左 --> 中
   2. N         左 --> 右
   3. 1 ~ N-1   中 --> 右
 */

func hanoi1(n int)  {
   leftToRight(n)
}


// 把1~N层圆盘,从左 -> 右
func leftToRight(n int)  {   //1-n层全部圆盘
	if n == 1 { //base case 只剩一个
		fmt.Println("Move 1 from left to right")
		return
	}
	leftToMid(n - 1)
	fmt.Println("Move", n , "from left to right")
	midToRight(n - 1)
}

// 把1~N层圆盘,从左 -> 中
func leftToMid( n int)  {
	if n == 1 {
		fmt.Println("Move 1 from left to mid")
		return
	}
	leftToRight(n - 1)
	fmt.Println("Move",n,"from left to mid")
	rightToMid(n - 1 )
}


// 把1~N层圆盘,从 右 -> 中
func rightToMid(n int){
   if n == 1 {
	   fmt.Println("Move 1 from right to mid")
	   return
   }
   rightToLeft(n - 1)
   fmt.Println("Move",n,"from right to mid")
   leftToMid(n - 1)
}


func midToRight(n int)  {
   if n == 1 {
	   fmt.Println("Move 1 fromo mid to right")
	   return
   }
   midToLeft(n - 1)
   fmt.Println("Move",n,"from mid to right")
   leftToRight(n - 1)
}


func rightToLeft(n int)  {
	if n == 1 {
		fmt.Println("Move 1 from right to left")
		return
	}
	rightToMid(n - 1)
	fmt.Println("Move",n,"from right to left")
	midToLeft(n - 1)
}

func midToLeft(n int)  {
   if n == 1 {
	   fmt.Println("Move 1 from mid to left")
	   return
   }
   midToRight(n - 1)
   fmt.Println("Move",n,"from mid to left")
   rightToLeft(n - 1)
}

func TestHanoi1(t *testing.T)  {
	hanoi1(3)
}

/*
 1. 1~N-1   from  -> other
 2. N       from  -> to
 3. 1~N-1   other -> to
 */

func hanoi2(n int)  {
	if n > 0 {
		hanoi(n,"left","right","mid")
	}
}

func hanoi(N int, from, to, other string)  {
	if N == 1 {
		fmt.Println("Move 1 from",from,"to",to)
		return
	}else {
		hanoi(N - 1,from , other,to)
		fmt.Println("Move",N,"from",from,"to",to)
		hanoi(N-1,other,to,from)
	}
}

func TestHanoi2(t *testing.T)  {
	hanoi2(10)
}


/*
 3层为例


1.  1,2   左 --> 中                   | 1 左 --> 右
                                     | 2 左 --> 中
                                     | 1 右 --> 中
2.  3     左 --> 右

3.  1,2   中 --> 右                   | 1 中 --> 左
                                     | 2 中 --> 右
                                     | 1 左 --> 右


N层汉诺塔最优解复杂度O(2^N-1)
 */







type Record struct {
	finish bool
	base   int
	from   string
	to     string
	other  string
}

type RecordStack struct {
	Elem []Record
}

func NewRecordStack() *RecordStack {
	return &RecordStack{Elem: make([]Record,0)}
}

func (s *RecordStack)Push(val Record)  {
	s.Elem = append(s.Elem, val)
}

func (s *RecordStack)Pop() Record {
	res := s.Elem[len(s.Elem)-1]
	s.Elem = s.Elem[:len(s.Elem)-1]
	return res
}

func (s *RecordStack)Peek() *Record {
	return &s.Elem[len(s.Elem)-1]
}

func (s *RecordStack)IsEmpty() bool  {
	return len(s.Elem) == 0
}

func hanoi3( N int) {
    if N < 1 {
		return
	}

	stack := NewRecordStack()
	stack.Push(Record{
		finish: false,
		base:   N,
		from:   "left",
		to:     "right",
		other:  "mid",
	})


	for !stack.IsEmpty() {
		cur := stack.Pop()
		if cur.base == 1 {
			fmt.Println("Move 1 from",cur.from,"to",cur.to)
			if !stack.IsEmpty() {
				stack.Peek().finish = true
			}
		}else {
			if !cur.finish {
				stack.Push(cur)
				stack.Push(Record{
					finish: false,
					base:   cur.base-1,
					from:   cur.from,
					to:     cur.other,
					other:  cur.to,
				})
			}else {
				fmt.Println("Move",cur.base,"from",cur.from,"to",cur.to)
				stack.Push(Record{
					finish: false,
					base:   cur.base-1,
					from:   cur.other,
					to:     cur.to,
					other:  cur.from,
				})
			}
		}
	}


}

func TestHanoi3(t *testing.T)  {
	hanoi3(3)
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

metabit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值