分治法

分治法的思想

分治法的思想像是分开求解然后和并,原问题从而得到解决。分治法的思想在算法设计中广泛使用,例如归并排序、快速排序、二分查找等等。

分治法解题思路

  1. 分解问题:将原问题分解为范围更小的几个同类问题
  2. 求解问题:求解这些范围更小的子问题
  3. 和并问题:和并子问题的解得到原问题的解

分治法的难点

  1. 如何分解问题
  2. 如何和并问题
    分治法求解问题采用分而治之的思想,但是代码似乎采用递归的样式。对于有些简单的方法,对问题进行分解后,子问题即是原问题的解,这个时候就不需要和并问题这一步(其实是减治法,例如二分查找)。

典型例题

二分查找

问题分析

将查找区间分为两个区间,通过判断中间值可以得出原问题的答案位于哪个区间,在这个区间再次利用这种方法,最终找出答案。
用到了分治法解题步骤中的1、2

代码

#include 
#include 
#include 
using namespace std;

class BinarySearch{
public:
    static int binarySearch(int* a, int first ,int last,int key){
        assert(a != 0);
        if (first <= last){
            int mid = first + ((last - first) >> 1);
            if (a[mid] == key){
                return mid;
            }else if (a[mid] > key){
                binarySearch(a, first, mid - 1, key);
            }
            else{
                binarySearch(a, mid + 1, last, key);
            }
        }
        else{
            return -1;
        }
    }
};

int main(){
    int a[] = { 1, 4, 9, 17, 24, 29, 32 };
    cout << BinarySearch::binarySearch(a, 0, sizeof(a) / sizeof(int), 9) << endl
        << BinarySearch::binarySearch(a,0,sizeof(a)/sizeof(int),10)<return 0;
}

归并排序

思路
  1. 将待排序区间分解为只有一个元素的区间
  2. 因为一个元素的区间本身就是有序的,所以子问题不需要求解
  3. 将子区间和并成大的有序区间,然后和并成为有序区间
代码

class MergeSort{
public:
    static void merge(int* a, int first,int last){
        int* temp = new int[last - first];
        merge(a, temp, first, last-1);
        delete[] temp;
    }
private:
    static void merge(int* a, int* d, int l, int h){
        if (l < h){
            int mid = l + ((h - l) >> 1);
            merge(a, d, l, mid);
            merge(a, d, mid + 1, h);
            And(a, d, l, mid + 1, h);//和并
        }
        //else不需要求解
    }
    //两个有序序列的和并
    static void And(int* a, int* d, int l1, int l2, int h2){
        int h1 = l2 - 1;
        int i = l1;
        int j = l1;
        while (l1 <= h1 && l2 <= h2){
            if (a[l1] <= a[l2]){
                d[i++] = a[l1++];
            }
            else{
                d[i++] = a[l2++];
            }
        }
        while (l1 <= h1){
            d[i++] = a[l1++];
        }
        while (j < i){
            a[j] = d[j];
            ++j;
        }
    }

};

逆序对


class ReverseOrderPair{
public:
    static int merge(int* a, int first, int last){
        int* temp = new int[last - first];
        int count = merge(a, temp, first, last-1);
        delete[] temp;
        return count;
    }
private:
    static int AndCount(int* a, int* d, int l1, int l2, int h2){
        int h1 = l2 - 1;
        int i = l1;
        int j = l1;
        int count = 0;
        while (l1 <= h1 && l2 <= h2){
            if (a[l1] <= a[l2]){
                d[i++] = a[l1++];
            }
            else{
                d[i++] = a[l2++];
                count += h1 - l1 + 1;//l1当前区间内可以与a[l2]构成逆序对的个数
            }
        }
        while (l1 <= h1){
            d[i++] = a[l1++];
        }
        while (j < i){
            a[j] = d[j];
            ++j;
        }
        return count;
    }

    static int merge(int* a, int* d, int l, int h){
        if (l < h){
            int mid = l + ((h - l) >> 1);
            int c1 = merge(a, d, l, mid);
            int c2 = merge(a, d, mid + 1, h);
            int c3 = AndCount(a, d, l, mid + 1, h);
            return c1 + c2 + c3;
        }
        else{
            return 0;
        }
    }

};

你可能感兴趣的:(C/C++)