分治法簡述

2021-10-02 16:09:25 字數 3460 閱讀 1402

許多有用的演算法在結構上是遞迴的:為了解決乙個給定的問題,演算法一次或多次的遞迴呼叫其自身已解決緊密相關的若干子問題。這些演算法典型的遵循分治法的思想:既將原問題分解為幾個規模較小但類似於原問題的子問題,遞迴的求解這些子問題,然後再合併這些子問題的解來建立原問題解

分治模式在每層遞迴時有三個步:

分解:分解原問題為若干問題。這些子問題是原問題的規模較小的例項

解決:解決這些子問題遞迴地求解每個子問題,然後若子問題的規模足夠小就直接求解。

合併:合併這些子問題的解推出原問題的解。

嗯,上面幾句就我們老師給我們講的,字很少,但聽不懂對吧~>_< ~ 我開始也是這樣,

咱就講個例項吧,話不多說,開始

因為我也是簡單的了解,所以就不像隔壁大佬那樣上綱上線,我們從最基礎的歸併排序來食用(了解)分治模式

歸併排序作為學生必須掌握的幾個演算法之一(反正我老師是這麼說的,我是看完書再跑過來嘮嗑的)套用上面三個步驟

分解:將待排序的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();}}

講到這裡就算了,按慣例來張執行結果圖鎮宅:

沒錯,寫了這麼多就是為了輸出這幾個數

分治法排序

分治法排序 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...