分治算法總結

分治法學習總結

分治法是我們經常用到的算法,合理利用分治算法可以使我們更好的解決問題。我們在使用二分查找、歸併排序的時候都要用到分治算法。下面我將從三個方面介紹分治算法,方便我們更好的瞭解和學習分治算法。
1.分治算法介紹
2.分治算法應用分析
3.分治算法例題分析

1.分治算法介紹

1.基本概念

分治算法的基本思想是將一個規模爲N的問題分解爲K個規模較小的子問題,這些子問題相互獨立且與原問題性質相同。求出子問題的解,就可得到原問題的解。即一種分目標完成程序算法,簡單問題可用二分法完成。

2.解題思路

1、原問題可以分解爲多個子問題
這些子問題與原問題相比,只是問題的規模有所降低,其結構和求解方法與原問題相同或相似。
2、原問題在分解過程中,遞歸地求解子問題
由於遞歸都必須有一個終止條件,因此,當分解後的子問題規模足夠小時,應能夠直接求解。
3、在求解並得到各個子問題的解後
應能夠採用某種方式、方法合併或構造出原問題的解。
不難發現,在分治策略中,由於子問題與原問題在結構和解法上的相似性,用分治方法解決的問題,大都採用了遞歸的形式。在各種排序方法中,如歸併排序、堆排序、快速排序等,都存在有分治的思想 。

2.分治算法應用分析

先讓我們通過一個簡單的二分查找來理解分治算法的基本思路。

public static int commonBinarySearch(int[] arr,int key){
        int low = 0;
        int high = arr.length - 1;
        int middle = 0;         //定義middle
        
        if(key < arr[low] || key > arr[high] || low > high){
            return -1;              
        }
        
        while(low <= high){
            middle = (low + high) / 2;
            if(arr[middle] > key){
                //比關鍵字大則關鍵字在左區域
                high = middle - 1;
            }else if(arr[middle] < key){
                //比關鍵字小則關鍵字在右區域
                low = middle + 1;
            }else{
                return middle;
            }
        }
        
        return -1;      //最後仍然沒有找到,則返回-1
    }

首先先在排序的數組找到中間值,定義我們的中間值,找到就返回,找不到就在符合條件的子問題繼續二分,直到滿足邊界條件退出循環。

1.歸併排序

歸併排序(MERGE-SORT)是利用歸併的思想實現的排序方法,該算法採用經典的分治(divide-and-conquer)策略(分治法將問題分(divide)成一些小的問題然後遞歸求解,而治(conquer)的階段則將分的階段得到的各答案"修補"在一起,即分而治之)。
第一, 分解: 把待排序的 n 個元素的序列分解成兩個子序列, 每個子序列包括 n/2 個元素.
第二, 治理: 對每個子序列分別調用歸併排序MergeSort, 進行遞歸操作
第三, 合併: 合併兩個排好序的子序列,生成排序結果.


public static int[] sort(int[] a,int low,int high){
        int mid = (low+high)/2;
        if(low<high){
            sort(a,low,mid);
            sort(a,mid+1,high);
            //左右歸併
            merge(a,low,mid,high);
        }
        return a;
    }
     
    public static void merge(int[] a, int low, int mid, int high) {
        int[] temp = new int[high-low+1];
        int i= low;
        int j = mid+1;
        int k=0;
        // 把較小的數先移到新數組中
        while(i<=mid && j<=high){
            if(a[i]<a[j]){
                temp[k++] = a[i++];
            }else{
                temp[k++] = a[j++];
            }
        }
        // 把左邊剩餘的數移入數組 
        while(i<=mid){
            temp[k++] = a[i++];
        }
        // 把右邊邊剩餘的數移入數組
        while(j<=high){
            temp[k++] = a[j++];
        }
        // 把新數組中的數覆蓋nums數組
        for(int x=0;x<temp.length;x++){
            a[x+low] = temp[x];
        }
    }
2.快速排序

給定數組int[]a={7,5,3,2,9,10,8,4,6,1};
第1步:找基準值
所謂的基準值,顧名思義就是以它爲基準進行比大小。通常來說,我們選取數組的第一個數爲基準值。在數組a裏基準值就是7.
第2步:比大小
先從數組的最右邊開始往左邊找比基準值小的第一個數,然後從數組的最左邊開始往右找比基準值大的第一個數。那麼爲什麼要這麼找呢?因爲現在我們要把數組從小到大排序,所以要找出比基準值小的數放到基準值的左邊,找出比基準值的數放在基準值的右邊。
那麼在數組a裏,從左往右找,第一個比7大的數就是9,我們把它的座標記爲i;從右往左找,第一個比7小的數就是1,我們把它的座標記爲j。
第3步:交換
找到之後,如果這個時候i<j,那麼就交換這兩個數,因爲i=4,j=9,符合條件,將9和1進行交換。現在數組變成了int[]a={7,5,3,2,1,10,8,4,6,9};
如果j>=i,那麼不做處理
爲什麼還要判斷i和j的大小呢?就像第二步說的,我們要找出比基準值小的數放到基準值的左邊,找出比基準值的數放在基準值的右邊。所以如果i<j的話,交換就達到目的了,如果i>=j,比基準值小的數就在基準值的左邊,比基準值大的數已經在基準值的右邊了,這時候就沒必要交換了。
第4步:繼續查找
在i<j的前提下,繼續向右查找比基準值大的數,往左找比基準值小的數,然後交換。
在我們的例子中,10和6、8和4都符合交換的條件,所以數組就變成了
int[]a={7,5,3,2,1,6,4,8,10,9};這時候i=6,j=7
第5步:交換基準值到合適的位置
當查找繼續進行,這時候i=j=6,已經不滿足繼續查找和交換的條件了,那麼我們應該怎麼辦呢?答案就是把a[6]和基準值交換,因爲i=j的時候說明已經到了一個分界線的位置,分界線左邊的數比基準值小,分界線右邊的數比基準值大,而這個分界線就是我們的基準值,所以把它和a[i]交換,這時候數組就變成:
int[]a={4,5,3,2,1,6,7,8,10,9};
第6步:重複
對基準值左右兩邊的兩個子數組重複前面五個步驟直至排序完成。

分治算法例題分析

最大子序和

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章