遞迴入門(漢諾塔問題)

2022-09-22 06:18:11 字數 3858 閱讀 7644

遞迴是演算法課中最重要的一門必修課,也是我們繞不開的坎,寫這篇文章的目的主要是以練代學,一步一步理解遞迴,形成肌肉記憶

有很多理論性的文章,教你如何理解遞迴,看完之後還是很懵逼,最初我學遞迴的時候直接是從入門到放棄,然後打算直接刷題,在題量的累積下,頓悟了

概念上的東西不解釋太多,簡單說一下就是,有三根柱子 a (左),b() , c 。現在要把 a 柱上的盤子全部移到 b 柱上,移動過程中必須遵守乙個原則:只有小盤子才能壓在**子上

因為一次我們只能移動乙個盤子,所以需要移動 7 次才可解決問題,即:

把 小盤 從 左 移到 右

把 中盤 從 左 移動 中

把 小盤 從 右 移到 左

最大的盤子 從 左 移到 右

把 小盤 從 **中 -> 左 **

中盤 從中 -> 右

最後一步 :小盤 從左 -> 右

過程很簡單,因為一次只能移動最頂上的盤子,所以我們要移動**子,就要把它上面的小盤子全部移走才行

我們來看一下coding

public static void hanoi(int n) 

private static void lefttoright(int n)

// 把 n-1 層盤子從左移到中,

// 再把最底下的盤子移到右,再把中間的 n-1 層盤子移到右

lefttomid(n - 1);

system.out.println("move " + n + " from left to right");

midtoright(n - 1);

}

是不是很簡單

我們再看一下 lefttomid 方法怎麼寫

還是和之前一樣分析, 我們要把 n 層盤子從左移到中,就需要先把 n-1 個盤子從左挪到右,然後把左邊最底下的盤子挪到中,然後再把 n-1 層盤子從右邊挪到中間

private static void lefttomid(int n) 

// 要把 n 層盤子從左挪到中,需要先把 n-1 層挪出去給第 n 層騰位置

// 所以把 n-1 層從左挪到右

lefttoright(n - 1);

// 再把第 n 層挪到中

system.out.println("move " + n + " from left to mid");

// 再把挪到右邊的 n-1 層挪回來

righttomid(n - 1);

}

完整**如下:

public static void hanoi(int n) 

/** * 把 n 層圓盤,從左 -> 右

* @param n

*/private static void lefttoright(int n)

// 把 n-1 層盤子從左移到中,

// 再把最底下的盤子移到右,再把中間的 n-1 層盤子移到右

lefttomid(n - 1);

system.out.println("move " + n + " from left to right");

midtoright(n - 1);

}private static void lefttomid(int n)

// 要把 n 層盤子從左挪到中,需要先把 n-1 層挪出去給第 n 層騰位置

// 所以把 n-1 層從左挪到右

lefttoright(n - 1);

// 再把第 n 層挪到中

system.out.println("move " + n + " from left to mid");

// 再把挪到右邊的 n-1 層挪回來

righttomid(n - 1);

}private static void righttomid(int n)

righttoleft(n - 1);

system.out.println("move " + n + " from right to mid");

lefttomid(n - 1);

}private static void righttoleft(int n)

righttomid(n - 1);

system.out.println("move " + n + " from right to left");

midtoleft(n - 1);

}private static void midtoleft(int n)

midtoright(n - 1);

system.out.println("move " + n + " from mid to left");

righttoleft(n - 1);

}private static void midtoright(int n)

midtoleft(n - 1);

system.out.println("move " + n + " from mid to right");

lefttoright(n - 1);

}

這就是傻白甜的漢諾塔問題

這個過程我們可以優化一下,我們先忘掉左中右,假如我們現在還是有三個柱子:from,to,other

我們需要把 n 層盤子從 from 挪到 to 去,首先我們要把 n-1 層盤子挪到 other 上,然後把 n 從 from 挪到 to, 再把 other 上的 n-1 層盤子挪到 to,other 作為騰位置的柱子。

優化後的**:

public static void hanoi2(int n) 

} public static void func(int n, string from, string to, string other)

// 把 n-1 層從 from 挪到 other 上,to 充當騰位置的柱子

func(n - 1, from, other, to);

system.out.println("move " + n + " from " + from + " to " + to);

// 把 n-1 層從 other 挪到 to ,from 充當騰位置的柱子

func(n - 1, other, to, from);

}

這是我寫遞迴入門的第一篇文章,後面會繼續**包括 記憶化遞迴,遞迴到動態規劃等

我最開始學遞迴的時候,也覺得遞迴是一門玄學,不過這都不重要

重要的是我們需要有黑盒思維,什麼是黑盒思維?

就是我們不用關注這個 api 是怎麼實現的,我們只需要知道他能返回給我們需要的結果即可

C語言 遞迴入門 漢諾塔問題

在定義乙個過程或函式時,出現呼叫本過程或本函式的成分稱為遞迴 如果乙個遞迴過程或函式中的遞迴呼叫語句是最後一條執行語句,則稱這種遞迴呼叫為尾遞迴 例如 計算階乘函式 intf int n else return f n 1 n 遞迴解決問題應滿足三個條件 需要解決的問題可以轉化為乙個或多個子問題求解...

漢諾塔問題(遞迴)

題目描述 對於傳統的漢諾塔遊戲我們做乙個拓展,我們有從大到小放置的n個圓盤,開始時所有圓盤都放在左邊的柱子上,按照漢諾塔遊戲的要求我們要把所有的圓盤都移到右邊的柱子上,請實現乙個函式列印最優移動軌跡。給定乙個int n,表示有n個圓盤。請返回乙個string陣列,其中的元素依次為每次移動的描述。描述...

漢諾塔問題(遞迴)

問題 漢諾塔問題 解法 遞迴求解 思路 先把n 1從a移動b 在把第n個從a移到c 使用遞迴使得 變得簡單 複雜度 2的n次方 1 includeint step 1 void hanoi int level,char a,char b,char c 1 當盤子數大於1時,先把n 1個從a借助c移動...