Tower of Hanoi---C代码实现与力扣题目的应用

Tower of Hanoi

相传在很久以前,有个寺庙里的几个和尚整天不停地移动着 64 个盘子,日复一日,年复一年。据说,当 64 个盘子全部移完的那一天就是世界末日…

问题描述
有 A,B,C 三根柱子,A 上面有 n 个盘子,我们想把 A 上面的盘子移动到 C 上,但是要满足以下三个条件:

·每次只能移动一个盘子;
·盘子只能从柱子顶端滑出移到下一根柱子;
·盘子只能叠在比它大的盘子上。

在这里插入图片描述

分析:

这是一道经典的函数递归问题,也是一道递归的入门题目,直接进行分析较难看出,故我们可以先从一些简单的情况进行分析;
如果汉诺塔只有3层:
第一步我们要把第一个从A放到C,然后第二个放到B,然后把第一个再从C放到B,之后此时就可以把第三个放到C,之后再把第一个从B放到A,把第二个放到C然后第一个再放到C。
用图表示即为:
在这里插入图片描述

所以可知,我们要完成此问题第一步需要的就是先把最后一个上面的所有层都放到B上,然后最后一个抽出来放到C上,然后再把B上的放到C上。
之所以这样操作的原因是因为A上的最后一个也必须是C上的最后一个。

因此当64层时我们可以先分解一下这个大问题为三个步骤:

1.将A上的前63个借助C移动到B。
2.将A上的第64个直接移动到C。
3.将B上的63个借助A到C。

此时我们惊讶的发现将原先64层的问题分解为了63层
而由于我们的大问题其实就是“将A上的前64个借助B移动到C”。将他与上面的步骤1与3观察可知格式完全相同,只是层数和起点,终点,借助的点变了而已。即我们不难发现分出来的步骤1,3其实也是一种汉诺塔问题,只不过是层数和针的位置发生了改变

我们此时其实还可以对步骤1再进行一次分解观察:
他也可以分成三个步骤:

1.将A上的前62个借助B移动到C。
2.将A上的第63个直接移动到B。
3.将C上的62个借助A移动到B。

由此我们可以得出规律----即按照此步骤进行分解,使得每一个分出来的步骤都是一个独立的汉诺塔问题!!!
因此可以使用递归的方法进行多次求解。即对于此问题我们先进行不断的分解,直到分解到直接可以“挪移”的情况,我们再开始“挪移”。

C代码:

#include<stdio.h>
void hanoi(int n,char A,char B,char C)//此为进行“挪移”的函数
{
    
    //需要注意的是这里的A,B,C并不是单纯的指原先题目给的A针B针C针,这里是A指起点,B为借助的点,C为移动到的终点
	if(n==1)
	{
    
    
		printf("%c --> %c\n",A,C);//一层时直接从起点挪移到终点(A,C不代表某根针)
	}
	else
	{
    
    
		hanoi(n-1,A,C,B);
		printf(" %c --> %c\n",A,C);//挪移操作,即原步骤2
		hanoi(n-1,B,A,C); 
	}
}
int main()
{
    
    
	int n;
	printf("Please enter the number of floors of Hanoi tower:\n");
	scanf("%d",&n);
	hanoi(n,'A','B','C');//先把初始顺序和初始层数放进去
	return 0;	
} 

为了防止迷惑A,B,C为起点,中间点,终点,我又写了一个:

#include<stdio.h>
void hanoi(int n,char start,char middle,char end)
{
    
    
	if(n==1)
	{
    
    
		printf("%c --> %c\n",start,end);
	}
	else
	{
    
    
		hanoi(n-1,start,end,middle);
		printf(" %c --> %c\n",start,end);
		hanoi(n-1,middle,start,end); 
	}
}
int main()
{
    
    
	int n;
	printf("Please enter the number of floors of Hanoi tower:\n");
	scanf("%d",&n);
	hanoi(n,'x','y','z');
	return 0;	
} 

在力扣中同理解决—

面试题 08.06. 汉诺塔问题

在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:
(1) 每次只能移动一个盘子;
(2) 盘子只能从柱子顶端滑出移到下一根柱子;
(3) 盘子只能叠在比它大的盘子上。

请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子。

你需要原地修改栈。

示例1:

输入:A = [2, 1, 0], B = [], C = []
输出:C = [2, 1, 0]
示例2:

输入:A = [1, 0], B = [], C = []
输出:C = [1, 0]

提示:
A中盘子的数目不大于14个。

代码实现:

#define MAX_LEN 200
typedef struct {
    
    
    int* data;
    int size;
}Stack;
int cnt = 0;
void Push(Stack* s, int d)
{
    
    
    s->data[s->size++] = d;
}
int Pop(Stack* s){
    
    
    return s->data[--s->size];
}

void hannuota(int n, Stack* A, Stack* B, Stack* C){
    
    
    if(n == 1){
    
    
        cnt ++;
        Push(C, Pop(A));
        return;
    }
    hannuota(n-1, A, C, B);
    hannuota(1, A, B, C);
    hannuota(n-1, B, A, C);
}

void hanota(int* A, int ASize, int* B, int BSize, int** C, int* CSize){
    
    
    if(ASize <= 0) return;
    Stack X,Y,Z;
    X.data = A;
    X.size = ASize;
    Y.data = (int*)malloc(sizeof(int)*MAX_LEN);
    Y.size = 0;
    int *p = (int*)malloc(sizeof(int)*MAX_LEN);
    Z.data = p;
    Z.size = 0;
    hannuota(ASize, &X, &Y, &Z);
    *C = p;
    *CSize = Z.size;
    free(Y.data);
}

猜你喜欢

转载自blog.csdn.net/xiangguang_fight/article/details/112239914