天天看點

raptor輸入n個資料排序_如何運用遞歸思維解決問題——冒泡、選擇、合并排序...

raptor輸入n個資料排序_如何運用遞歸思維解決問題——冒泡、選擇、合并排序...

學習遞歸的目的,最終是運用遞歸解決問題。

了解遞歸的運作模型(https://zhuanlan.zhihu.com/p/166173378)之後,就能根據遞歸函數的靜态代碼推算執行結果了。實際上,對遞歸函數的執行結果的推算,可從另一個途徑進行,即運用類似于數學歸納法的思想。下面以計算階乘的遞歸函數為例說明。

raptor輸入n個資料排序_如何運用遞歸思維解決問題——冒泡、選擇、合并排序...

考察遞歸函數int

fact(int n)

1.它确實能正确計算0的階乘的值;

2.當執行函數fact(1)調用時,它傳回的值是1* fact(0),即1,是以1!計算正确。

3.當執行函數fact(2)調用時,它傳回的值是2* fact(1),隻要fact(1)能計算正确(上一步驟已證明正确),那麼fact(2)也能正确計算2!

……

4.當執行函數fact(n)調用時,它傳回的值是n*fact(n-1),從計算式子可推斷出,隻要fact(n-1)能計算出(n-1)!,那麼,fact(n)就能計算出n!

根據數學歸納法的思想,就推斷證明了fact(n)能計算出n!

切入正題——用遞歸思維程式設計解決問題

當描述問題解答的算法本身是遞歸式子時,我們很容易寫出程式的遞歸函數。

對于一般的問題,設計遞歸函數的步驟、方法如下:

1.首先要明确地描述問題、定義問題,

設計函數首部

,用函數的參數刻畫待解決問題的數量特征及其關系本質,特别地,函數參數(即變量)描述問題的規模,并描述函數的功能,或者說要非常明确函數要完成的任務,對設計者來說,無論口頭和書面,都能清晰地、準确無誤地、一般化地描述。

2.遞歸函數函數體的程式架構:

raptor輸入n個資料排序_如何運用遞歸思維解決問題——冒泡、選擇、合并排序...

确定最小問題,即确定遞歸邊界,直接解決最小問題;

當問題規模較大時,對問題進行分解,用遞歸調用解決分解出的小問題,用小問題的解構造出函數首部定義的原問題的解。

遞歸的三要素

:定義描述問題;解決最小問題;分解大問題、用遞歸解決分解出的小問題。

用遞歸思維解決問題,我們不必關注如何處理及求解問題的詳細過程和步驟,你甚至可以不知道計算解題過程就把問題給程式設計解決了。豈不是美死了!!!就像孫悟空懂規則,但不知道具體如何玩漢諾塔,可他居然完成了移動漢諾塔的目标(https://zhuanlan.zhihu.com/p/168684834)。

在一定的時間、空間限制下,人的體力有限,思維力也有限,遞歸思維對實踐最有用的指導,就是把腦力集中于定義問題這個關鍵點上,不用去找解題的過程。定義(問題)即解決(問題),

定義即解決! 定義即解決!! 定義即解決!!!

有點像具備先進飛彈的現代先進戰鬥機,它們具備“

發現即摧毀

”的能力。

上面說的是不是讓人覺得雲裡霧裡,是不是吹牛。馬上給您醍醐灌頂。

例1

輸入整數n,輸出1~n的整數

例如n=5時,輸出12345。 這例子夠簡單。

問題:要解決的問題直截了當,即輸出1~n的整數,設計函數首部void prn1n(int n);确定并解決最小問題;定義函數void prn1n(int n)明确其任務後,“

定義即解決

”指的是在設計函數體時,認為比1~n規模小的問題都已得到解決,都立即為我所用,即輸出1~n-1或1~n-2的問題等,立即用遞歸得到解決。

raptor輸入n個資料排序_如何運用遞歸思維解決問題——冒泡、選擇、合并排序...

我們還可以這樣定義問題題:輸出s~t之間的整數,函數首部void prnst(int s,int t); 表示輸出s~t之間的整數;确定并解決最小問題;定義函數void prnst(int s,int t) 明确其任務後,“

定義即解決

”指的是在設計函數體時,認為比s~t規模小的問題都已得到解決,都立即為我所用,例如輸出s+1~t、s+1~t-1或s~t-2或s~(s+t)/2等等,做法分别是prnst(s+1,t)、prnst(s+1,t-1)、prnst(s,t-2)、prnst(s ,(s+t)/2)。是以,要寫出輸出s~t之間的整數的遞歸函數,容易之極。

raptor輸入n個資料排序_如何運用遞歸思維解決問題——冒泡、選擇、合并排序...
例1高明之處在于,簡單的輸出1~n之間的整數的問題,玩出如此之多的花樣,對于線性參數表示的問題,它的遞歸方式(對問題的切分方式)基本上類似于以上幾種方法之一。如數組的選擇、冒泡、快速、合并排序,一維的背包問題等等,概莫能外。 遞歸思維解題的另一個關鍵點是劃(切)分問題。 例2

冒泡排序,全遞歸實作。定義函數:void bubbleSort(int a[],int n); 它的任務是對數組a的前n個元素排序。 按照“

定義即解決

”原則,在設計函數體時,極易做到(用遞歸)排序數組a的前i(i<n)個元素。定義函數:void bubble(int a[],int n); 它的任務是對數組a的前n個元素進行冒泡處理,使a[n-1]最大。 按照“

定義即解決

”原則,在設計函數體時,極易做到(用遞歸)對數組a的前i(i<n)個元素冒泡,使a[i-1]最大。基于此,設計遞歸函數實作冒泡排序不費吹灰之力。

#include 
           
例3

合并排序。void mergeSort(int a[],int s,int t)與

例1

方法5的遞歸函數相似度驚人!!

#include 
           
例4

選擇排序,全遞歸實作

#include 
           

研究比較

例1

的各種遞歸方法,您很容易了解選擇排序、冒泡排序和合并排序以及其中的冒泡函數void bubble(int *a, int n)和函數void selectMin(int *a, int n)的遞歸實作。

趙馮平:遞歸思維——插入排序、快速排序的全遞歸實作

什麼是遞歸思維? 有請各位高見

趙馮平:了解遞歸函數調用的最好模型(沒有之一)​zhuanlan.zhihu.com

raptor輸入n個資料排序_如何運用遞歸思維解決問題——冒泡、選擇、合并排序...

趙馮平:漢諾塔、遞歸, 為什麼孫悟空可以輕松玩轉?​zhuanlan.zhihu.com

raptor輸入n個資料排序_如何運用遞歸思維解決問題——冒泡、選擇、合并排序...

繼續閱讀