分治算法

分治算法簡介

在計算機科學(xué)中,分治法是一種很重要的算法。字面上的解釋是“分而治之”鲫趁,簡單來說就是把一個問題分解為很多的子問題,然后再通過子問題的合并來獲得最終的結(jié)果捌锭。如:排序算法(歸并排序,快速排序)罗捎,傅立葉變換都屬于典型的分治算法的案例观谦。

基本思路

將一個個大問題,拆分成小問題桨菜,然后各個擊破豁状,把小問題的答案再合并成最終的答案。
如果一個問題能夠被拆成k個小問題倒得,并且這k個小問題的答案能夠合并成最終的答案泻红,那么就可以用分治算法來解決。

實際案例

案例一(歸并排序)

加入有一個無序的數(shù)組{5,4,3,2,1,6,8,7,10,1},要對他們進行歸并排序:
1.把數(shù)組持續(xù)拆分屎暇,直到只剩下一個元素為止
2.遞歸的合并拆分后的數(shù)組承桥,直到最后得到排序后的結(jié)果
代碼實現(xiàn):
1.拆分?jǐn)?shù)組:

 public static int[] sort(int[] arr,int left,int right){
        int index = left + (right - left)/2;
        if(left == right){
            int[] temp = new int[1];
            temp[0] = arr[left];
            return temp;
        } else{
            return compareSort(sort(arr,left,index),sort(arr,index+1,right));
        }
    }

2.合并數(shù)組:

public static int[] compareSort(int[] arr1,int[] arr2){
        int length = arr1.length + arr2.length;
        int index1 = 0, index2 = 0;
        int[] temp = new int[length];
        int index = 0;
        while(index1 < arr1.length && index2 < arr2.length){
            if(arr1[index1] < arr2[index2]){
                temp[index++] = arr1[index1++];
            }else{
                temp[index++] = arr2[index2++];
            }
        }
        while(index1 < arr1.length){
            temp[index++] = arr1[index1++];
        }
        while(index2 < arr2.length){
            temp[index++] = arr2[index2++];
        }
        return temp;
    }
案例二(快速排序)

從數(shù)列中挑出一個元素,稱為 “基準(zhǔn)”(pivot);
重新排序數(shù)列根悼,所有元素比基準(zhǔn)值小的擺放在基準(zhǔn)前面凶异,所有元素比基準(zhǔn)值大的擺在基準(zhǔn)的后面(相同的數(shù)可以到任一邊)。在這個分區(qū)退出之后挤巡,該基準(zhǔn)就處于數(shù)列的中間位置剩彬。這個稱為分區(qū)(partition)操作;

遞歸地(recursive)把小于基準(zhǔn)值元素的子數(shù)列和大于基準(zhǔn)值元素的子數(shù)列排序矿卑;

遞歸的最底部情形喉恋,是數(shù)列的大小是零或一,也就是永遠都已經(jīng)被排序好了母廷。雖然一直遞歸下去轻黑,但是這個算法總會退出,因為在每次的迭代(iteration)中琴昆,它至少會把一個元素擺到它最后的位置去氓鄙,具體步驟:
1.拆分?jǐn)?shù)組

public int[] quickSort(int[] arr, int left, int right) {
        int partitionIndex;
        if (left < right) {
            partitionIndex = partition(arr, left, right);
            quickSort(arr, left, partitionIndex - 1);
            quickSort(arr, partitionIndex + 1, right);
        }
        return arr;
    }

2.分區(qū)操作

public int partition(int[] arr, int left, int right) {     // 分區(qū)操作
        int pivot = left,                      // 設(shè)定基準(zhǔn)值(pivot)
                index = pivot + 1;
        for (int i = index; i <= right; i++) {
            if (arr[i] < arr[pivot]) {
                swap(arr, i, index);
                index++;
            }
        }
        swap(arr, pivot, index - 1);
        return index - 1;
    }
案例二(最近點問題)

假如平面上有N個散列的點,找到距離最短的兩個點抖拦。正常方法是,計算每任意兩個點之間的距離舷暮,這樣的話态罪,時間是N(N-1)/2,
也就是O(n
n);但是有一種方法,對于密集的點下面,能夠把效率提升為O(NlogN ),這種方式就是分治算法复颈。
假如如下圖,有下列密集點:

WX20190412-104120@2x.png

假如這些點已經(jīng)按照x軸進行排序诸狭,我們可以畫一條垂直的直線券膀,把點集分成兩半君纫,PL,PR,因此可以得出,整個點擊最近的兩個點一定是PL中最小的兩個點芹彬,和PR中距離最小的兩個點蓄髓,和PL中一個點和PR中一個點組成的一條最小距離的直線。正如下圖所示舒帮,整個點擊最小距離的點一定是dL,dR,和dc中最小的那一條会喝。


WX20190412-104749@2x.png

具體實現(xiàn)步驟:
1.通過不斷的遞歸從中拆分,直到左右兩邊只剩下兩個點為止玩郊。這樣的話肢执,dL,dR的距離直接通過計算可以得出,因此,可以設(shè)置 s = min(dL,dR);
2.計算dc的最短距離译红,由于我們知道中線的位置预茄,因此只需要計算 (mid-s)和(mid+s)中所有點的距離即可。
3.最后整個區(qū)域的最小值則為min(dL,dR,dC)

具體代碼實現(xiàn):
1.定義平面點的屬性:


public class Points{
    private double x,y;

    public void setX(double x) {
        this.x = x;
    }

    public double getX() {
        return x;
    }

    public void setY(double y) {
        this.y = y;
    }

    public double getY() {
        return y;
    }
}

2.遞歸拆分所有的點

public static double divPoints(Points[] points, int left, int right){
        if(right - left == 1){
            return distance(points[left],points[right]);
        }else if(right - left == 2){
            return distance(points[left],points[left+1],points[left+2]);
        }else{
            int mid = left + (right - left)/2;
            double leftP = divPoints(points,left,mid);
            double rightP = divPoints(points,mid,right);
            double minLR = Math.min(leftP,rightP);
            ArrayList<Points> dLeft = new ArrayList();
            ArrayList<Points> dRight = new ArrayList();
            for(int i = left; i <= right; i++){
                if(i != mid){
                    if(points[i].getX() < points[mid].getX() && (points[mid].getX() - points[i].getX()) < minLR ){
                        dLeft.add(points[i]);
                    }else if(points[i].getX() >= points[mid].getX() && (points[i].getX() - points[mid].getX()) < minLR){
                        dRight.add(points[i]);
                    }
                }
            }


            for(int i = 0;i<dLeft.size();i++){
                for(int j = 0;j<dRight.size();j++){
                    double mLR = distance(dLeft.get(i),dRight.get(j));
                    if(mLR < minLR){
                        minLR = mLR;
                    }
                }
            }
            return minLR;
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末侦厚,一起剝皮案震驚了整個濱河市耻陕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌刨沦,老刑警劉巖诗宣,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異想诅,居然都是意外死亡召庞,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進店門来破,熙熙樓的掌柜王于貴愁眉苦臉地迎上來篮灼,“玉大人,你說我怎么就攤上這事徘禁〈┪龋” “怎么了?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵晌坤,是天一觀的道長。 經(jīng)常有香客問我旦袋,道長骤菠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任疤孕,我火速辦了婚禮商乎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘祭阀。我一直安慰自己鹉戚,他們只是感情好鲜戒,可當(dāng)我...
    茶點故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著抹凳,像睡著了一般遏餐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赢底,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天失都,我揣著相機與錄音,去河邊找鬼幸冻。 笑死粹庞,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的洽损。 我是一名探鬼主播庞溜,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼碑定!你這毒婦竟也來了流码?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤不傅,失蹤者是張志新(化名)和其女友劉穎旅掂,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體访娶,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡商虐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了崖疤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秘车。...
    茶點故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖劫哼,靈堂內(nèi)的尸體忽然破棺而出叮趴,到底是詐尸還是另有隱情,我是刑警寧澤权烧,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布眯亦,位于F島的核電站,受9級特大地震影響般码,放射性物質(zhì)發(fā)生泄漏妻率。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一板祝、第九天 我趴在偏房一處隱蔽的房頂上張望宫静。 院中可真熱鬧,春花似錦、人聲如沸孤里。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捌袜。三九已至说搅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間琢蛤,已是汗流浹背蜓堕。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留博其,地道東北人套才。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像慕淡,于是被迫代替她去往敵國和親背伴。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,492評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 分冶算法的基本思想是將原問題分解為幾個規(guī)模較小的但類似原問題的子問題峰髓,遞歸地求解這些了問題傻寂,然后再合并這些子問題的...
    某昆閱讀 1,668評論 0 6
  • Divide-and-Conquer算法的設(shè)計 設(shè)計過程分為三個階段: Divide:整個問題劃分為多個子問題 C...
    三三de酒閱讀 3,256評論 0 4
  • 從分治算法說起 要說 MapReduce 就不得不說分治算法,而分治算法其實說白了携兵,就是四個字 分而治之 疾掰。其實就...
    大數(shù)據(jù)_zzzzMing閱讀 602評論 0 0
  • https://www.cnblogs.com/steven_oyj/archive/2010/05/22/174...
    麒麟楚莊王閱讀 572評論 0 0
  • 排序算法說明 (1)排序的定義:對一序列對象根據(jù)某個關(guān)鍵字進行排序; 輸入:n個數(shù):a1,a2,a3,…,an 輸...
    code武閱讀 653評論 0 0