《數(shù)據(jù)結(jié)構(gòu)與算法之美》32——分治算法

如何理解分治算法

分治算法(divide and conquer)的核心思想就四個(gè)字:分而治之夭坪,就是將原問題劃分成 n 個(gè)規(guī)模較小,并且結(jié)構(gòu)與原問題相似的子問題可很,遞歸地解決這些子問題橱乱,然后再合并其結(jié)果俱病,就得到原問題的解。

這個(gè)定義看起來(lái)有點(diǎn)類似遞歸的定義搂漠。分治和遞歸的區(qū)別是迂卢,分治算法是一種處理問題的思想,遞歸是一種編程技巧桐汤。實(shí)際上而克,分治算法一般比較適合用遞歸來(lái)實(shí)現(xiàn)。

分治算法的遞歸實(shí)現(xiàn)中怔毛,每一層遞歸都會(huì)涉及三個(gè)操作:

  • 分解:將原問題分解成一系列子問題员萍;
  • 解決:遞歸地求解各個(gè)子問題,若子問題足夠小拣度,則直接求解碎绎;
  • 合并:將子問題的結(jié)果合并成原問題;

分治算法能解決的問題抗果,一般需要滿足下面這幾個(gè)條件:

  • 原問題與分解成的小問題具有相同的模式筋帖;
  • 原問題分解成的子問題可以獨(dú)立求解,子問題之間沒有相關(guān)性窖张;
  • 具有分解終止條件幕随;
  • 可以將子問題合并成原問題,并且這個(gè)拿著操作的復(fù)雜度不能太高宿接;

分治算法應(yīng)用舉例分析

假設(shè)我們有 n 個(gè)數(shù)據(jù)赘淮,我們期望數(shù)據(jù)從小到大排列,那完全有序的數(shù)據(jù)的有序度就是 n(n-1)/2睦霎,逆序度等于0梢卸;相反,倒序排列的數(shù)據(jù)的有序度就是0副女,逆序度是 n(n-1)/2蛤高。除了這兩種 極端情況外,我們通過計(jì)算有序?qū)蛘吣嫘驅(qū)Φ膫€(gè)數(shù),來(lái)表示數(shù)據(jù)的有序度或逆序度戴陡。

如何編程求出一組數(shù)據(jù)的有序?qū)€(gè)數(shù)或者逆序?qū)€(gè)數(shù)呢塞绿?

image

最笨的方法是,拿每個(gè)數(shù)字跟它后面的數(shù)字比較恤批,看有幾個(gè)比它小的异吻。我們把比它小的數(shù)字 個(gè)數(shù)記作 k,通過這樣的方式喜庞,把每個(gè)數(shù)字都考察一遍之后诀浪,然后對(duì)每個(gè)數(shù)字對(duì)應(yīng)的k值求 和,最后得到的總和就是逆序?qū)€(gè)數(shù)延都。不過雷猪,這樣操作的時(shí)間復(fù)雜度是 O(n^2)

套用分治思想來(lái)求數(shù)組A的逆序?qū)€(gè)數(shù)晰房。我們可以將數(shù)組分成 前后兩半 A1 和 A2求摇,分別計(jì)算A1和A2的逆序?qū)€(gè)數(shù) K1 和 K2,然后再計(jì)算A1與A2之間的逆序?qū)?個(gè)數(shù) K3嫉你。那數(shù)組A的逆序?qū)€(gè)數(shù)就等于 K1+K2+K3月帝。

使用歸并排序算法來(lái)快速計(jì)算出兩個(gè)子問題 A1 與 A2 之間的逆序?qū)€(gè)數(shù)。求解過程如下圖:

image

代碼實(shí)現(xiàn):

var num = 0 // 全局變量或者成員變量
func count(a []int, n int) int {
    num = 0
    mergeSortCounting(a, 0, n-1)
    return num
}

func mergeSortCounting(a []int, p int, r int) {
    if p >= r {
        return
    }
    q := (p + r) / 2
    mergeSortCounting(a, p, q)
    mergeSortCounting(a, q+1, r)
    merge(a, p, q, r)
}

func merge(a []int, p int, q int, r int) {
    i, j, k := p, q+1, 0
    tmp := make([]int, r-p+1)
    for i <= q && j <= r {
        if a[i] <= a[j] {
            tmp[k] = a[i]
            k++
            i++
        } else {
            num += (q - i + 1) // 統(tǒng)計(jì)p-q之間幽污,比a[j]大的元素個(gè)數(shù)
            tmp[k] = a[j]
            k++
            j++
        }
    }
    for i <= q { // 處理剩下的
        tmp[k] = a[i]
        k++
        i++
    }
    for j <= r { // 處理剩下的
        tmp[k] = a[j]
        k++
        j++
    }
    for i := 0; i <= r-p; i++ { // 從tmp拷貝回a
        a[p+i] = tmp[i]
    }
}

分治思想在海量數(shù)據(jù)處理中的應(yīng)用

分治算法思想的應(yīng)用是非常廣泛的,并不僅限于指導(dǎo)編程和算法設(shè)計(jì)嚷辅。它還經(jīng)常用在海量數(shù)據(jù)處理的場(chǎng)景中。前面講的數(shù)據(jù)結(jié)構(gòu)和算法距误,大部分都是基于內(nèi)存存儲(chǔ)和單機(jī)處理簸搞。但是,如果要處理的數(shù)據(jù)量非常大准潭,沒法一次性放到內(nèi)存中趁俊,這個(gè)時(shí)候,這些數(shù)據(jù)結(jié)構(gòu)和算法就無(wú)法工作了刑然。

比如寺擂,給 10GB 訂單文件按照金額排序,而機(jī)器的內(nèi)存可能只有 2泼掠、3GB怔软,無(wú)法一次性加載到內(nèi)存,就無(wú)法單純地使用快排择镇、歸并等基礎(chǔ)算法來(lái)解決了挡逼。

要解決這種數(shù)據(jù)量大到內(nèi)存裝不下的問題,可以使用分治思想腻豌。將海量的數(shù)據(jù)集合劃分成幾個(gè)小的數(shù)據(jù)集合家坎,每個(gè)小的數(shù)據(jù)集合能夠單獨(dú)加載到內(nèi)存來(lái)解決嘱能,然后再將小數(shù)據(jù)集合合并成大數(shù)據(jù)集合。

比如剛剛舉的那個(gè)例子虱疏,給 10GB 的訂單排序惹骂,我們就可以先掃描一遍訂單,根據(jù)訂單的金 額订框,將 10GB 的文件劃分為幾個(gè)金額區(qū)間析苫。比如訂單金額為 1 到 100 元的放到一個(gè)小文件,101 到 200 之間的放到另一個(gè)文件穿扳,以此類推。這樣每個(gè)小文件都可以單獨(dú)加載到內(nèi)存排序国旷,最后將 這些有序的小文件合并矛物,就是最終有序的 10GB 訂單數(shù)據(jù)了。

參考資料

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末跪但,一起剝皮案震驚了整個(gè)濱河市履羞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌屡久,老刑警劉巖忆首,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異被环,居然都是意外死亡糙及,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門筛欢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)浸锨,“玉大人,你說(shuō)我怎么就攤上這事版姑≈眩” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵剥险,是天一觀的道長(zhǎng)聪蘸。 經(jīng)常有香客問我,道長(zhǎng)表制,這世上最難降的妖魔是什么健爬? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮夫凸,結(jié)果婚禮上浑劳,老公的妹妹穿的比我還像新娘。我一直安慰自己夭拌,他們只是感情好魔熏,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布衷咽。 她就那樣靜靜地躺著,像睡著了一般蒜绽。 火紅的嫁衣襯著肌膚如雪镶骗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天躲雅,我揣著相機(jī)與錄音鼎姊,去河邊找鬼。 笑死相赁,一個(gè)胖子當(dāng)著我的面吹牛相寇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播钮科,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼唤衫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了绵脯?” 一聲冷哼從身側(cè)響起佳励,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蛆挫,沒想到半個(gè)月后赃承,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡悴侵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年瞧剖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畜挨。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡筒繁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出巴元,到底是詐尸還是另有隱情毡咏,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布逮刨,位于F島的核電站呕缭,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏修己。R本人自食惡果不足惜恢总,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望睬愤。 院中可真熱鬧片仿,春花似錦、人聲如沸尤辱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至阳距,卻和暖如春塔粒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背筐摘。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工卒茬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人咖熟。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓圃酵,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親馍管。 傳聞我的和親對(duì)象是個(gè)殘疾皇子辜昵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359