許多有用的演算法在結構上是遞迴的:為了解決乙個給定的問題,演算法一次或多次的遞迴呼叫其自身已解決緊密相關的若干子問題。這些演算法典型的遵循分治法的思想:既將原問題分解為幾個規模較小但類似於原問題的子問題,遞迴的求解這些子問題,然後再合併這些子問題的解來建立原問題解
分治模式在每層遞迴時有三個步:
分解:分解原問題為若干問題。這些子問題是原問題的規模較小的例項
解決:解決這些子問題遞迴地求解每個子問題,然後若子問題的規模足夠小就直接求解。
合併:合併這些子問題的解推出原問題的解。
嗯,上面幾句就我們老師給我們講的,字很少,但聽不懂對吧~>_< ~ 我開始也是這樣,
咱就講個例項吧,話不多說,開始
因為我也是簡單的了解,所以就不像隔壁大佬那樣上綱上線,我們從最基礎的歸併排序來食用(了解)分治模式
歸併排序作為學生必須掌握的幾個演算法之一(反正我老師是這麼說的,我是看完書再跑過來嘮嗑的)套用上面三個步驟
分解:將待排序的n個元素序列分成倆個子序列,每個序列n/2個元素
解決:使用我們的歸併排序遞迴地將子串行兩個兩個排序
合併:合併兩個已排好的子串行變成乙個新的序列
(問一下:合併是什麼時候合併?)
ps:當我們的字問題無法再分出子問題的時候
所以當出現n 個子序列(它們的長度為1)時,我們就開始將分化出去的若干子問題「回公升」合併,而我們合併子串行的前提是什麼?----------(沒錯,就是子串行排好序了的時候);提一句乙個序列裡只有乙個元素它是不是已經排好了呢?當然是啦(你當它是最大值最小值都無所謂,反正就乙個數)
然後,重點來了, 歸併排序的關鍵體現在「合併」上,所以我們就定義乙個輔助過程merge(int a, int p, int q, int r), (懶癌晚期,變數名就這樣用吧)解釋一下:
/*** merge(int a, int p, int q, int r);實現合併兩個已經排好順序的序列
**@param a int陣列型別資料 原序列的子集
*@param p int型別資料 可以看成子串行a第乙個元素在初始序列中對應的下標
*@param q int型別資料 可以看成子串行a中間元素在初始序列中對應的下標
*@param r int型別資料 可以看成子串行a最後乙個元素在初始序列中對應的下表
*/先過一遍偽碼吧
merge(a, p, q,r)
//得到a序列劃分倆個子序列的個數
n1 = q -p+1
n2 = r-q
//將a序列分成倆個新的子串行(多留乙個位子存放哨兵)
let l[1..n1+1] and r[1..n2+1] be new arrys
for i== 1 to n1
l[i]
= a[p+i-1]
for j = 1 to n2
r[j]
= a[q+j]
//∞主要是用來在排序過程中表示該序列是否到底了,當然你也不可能取到無窮,這裡主要是為了理解
l[n1+1]
== ∞
r[n2+1]
== ∞
i = 1
j = 1
//排序合併兩個子串行
for k = p to r
if l[i]
<=r[j]
a[k]
= l[i]
i=i+1;
else a[k]
=r[j]
i=j+1
遞迴呼叫merge(a,p,q,r)
mergesort(a,p,r)
//跳出遞迴的條件,即p>=r時表明序列已達到最小,無法在分
if p
//獲取序列中間位子下標(向下取整)
q=(p+r)/2
//原序列左邊進行歸併排序
mergesort(a,p,q)
//原序列右邊進行歸併排序
mergesort(a,q+1,r)
//歸併兩個有序子串行,ok
merge(a,p,q,r)
到這裡大體思路都出來了
然後就是具體實現了:
//不會起名,就demo湊合著用吧
class
demo
;public
static
void
main
(string[
] args)
/** * merge(int a, int p, int q, int r);實現合併兩個已經排好順序的序列
* *@param p int型別資料 可以看成子串行a第乙個元素在初始序列中對應的下標
*@param q int型別資料 可以看成子串行a中間元素在初始序列中對應的下標
*@param r int型別資料 可以看成子串行a最後乙個元素在初始序列中對應的下表
*/public
static
void
merge
(int p,
int q,
int r)
for(
int j=
0; j<=n2-
1; j++
)/*因為個人比較懶,所以採用下面方式合併陣列,當然你自己也可以多寫幾個迴圈分情況合併,但我還是覺得下面的看起來舒服,
邏輯性很強,剛開始學的時候下面這種寫法我好久弄明白(不是**可讀性差哈),講遠了,因為下面需要用到乙個大的數字作
為『哨兵』放在陣列末尾,多大?正無窮?。。。。。表示不出來,所以我取了 2147483647(2^31 -1)int最大值*/
l[n1]
=2147483647
; r[n2]
=2147483647
;int i =0;
int j =0;
//因為'哨兵'的存在我們在比較過程作就不用時時刻刻去檢測陣列是否到頭了
for(
int k=p; k<=r; k++
)else}}
/** *遞迴呼叫mergesort方法,對應三個步驟中的:解決
* *@param p int型別資料 表示序列陣列起始下標
*@param r int型別資料 表示序列陣列起始結束下標
*/public
static
void
mergesort
(int p,
int r)
}//顯示陣列序列中數值
public
static
void
showvalueofarry
(int a)
system.out.
println();}}
講到這裡就算了,按慣例來張執行結果圖鎮宅:![](https://pic.w3help.cc/17e/cf591c7ea7aa182f632045b50c90b.jpeg)
沒錯,寫了這麼多就是為了輸出這幾個數
分治法排序
分治法排序 1 把大問題分為小問題 2 求每個小問題的解 3 和1反方向,把各個解合併起來 實現 1 啟用兩個快取,乙個放前半部份問題,乙個放後半部份問題 2 只用乙個大快取,用index的大小區分問題規模 include include void megre pre int pre,int fir...
分治法排序
include include define temp 10 int a temp int b temp void merge int low,int mid,int high else k while i mid while j high for i 0 i k i b low i a i int...
演算法 分治法
include function 列印int型陣列 parameter int型陣列,陣列的長度 void displayarray int a,int n printf n function 劃分由下標s開始到t終止的int陣列 parameter int型陣列,陣列的起始座標,陣列的終點座標 r...