zoukankan      html  css  js  c++  java
  • 分治算法及其案例用途

    分治算法也是一种重要的求解问题的思路,移用百科的定义,分治就是分而治之,就是将一个规模比较大的问题分解为几个规模较小的问题,这些规模较小的问题是相互独立的,但是它们与原问题性质相同,可以用相同的思路进行继续分解求解,最后将这些小规模的问题求解出的解合并起来作为原问题的解,故而分治算法的求解过程为:

    a、分解:寻找将原问题分解为求解几个规模比较小的问题,这些小问题和原问题的性值是相同的

    b、求解:将问题规模分解到一定程度,可以用简单的方法进行求解

    c、合并:将这些子问题的解合并起来作为原问题的解返回给调用者

    因为子问题和原问题是同构的,所以分治在一定程度上可以借助递归算法进行实现,递归算法更像是一种模板。以下是可以用分治算法思想的案例:

    1、归并排序

    归并排序是将问题先分解,然后进行排序,最后将小规模的排好序的子解合并为一个原问题的解,详见https://www.cnblogs.com/codeMedita/p/7412568.html

    2、求解最大值

    给定一个无序的数组arr,求解arr中的最大值,可有两种计算:

    a 直接遍历求解

    def maxVal(arr):

       int max=0;

       for val in arr:

         max=max>val?max:val;

       return max

    b 分治方法求解

    def dividAndConquer(arr,leftIndex,rightIndex):

      if(rightIndex==leftIndex+1 || rightIndex==leftIndex){

        return Math.max(arr[leftIndex],arr[rightIndex]);

      }

      int mid=(leftIndex+rightIndex)/2;

      int leftMax=dividAndConquer(arr,leftIndex,mid);

      int rightMax=dividAndConquer(arr,mid,rightIndex);

      return Math.max(leftMax,rightMax);

    3、二分查找,给定一个从小到大有序的数组和一个值,求解改值在数组中的位置

    def binarySearch(arr,leftIndex,rightIndex,val):

      if(leftIndex>rightIndex) return false;

      if(leftIndex==rightIndex):

        return arr[leftIndex]==val;

      int mid=(leftIndex+rightIndex)/2;

      if(arr[mid]==val) return true;

      if(arr[mid]>val){

        if(leftIndex==mid) return false;

        return binarySearch(arr,leftIndex,mid-1,val);

      }   

      return binarySearch(arr,mid+1,right,val);

    4、输出一条线上距离最近的两个点之间的距离值,给定一个数组arr,其值是从小到大有序的,输出最近点的距离

    def minDistance(arr,left,right):

      //同一个点返回极大值

      if(arr[left]==arr[right]) return Integer.MAX

          //相邻点的距离

      if(right==left+1) return arr[right]-arr[left];

      int mid=(left+right)/2;

      //中间点的临近点的距离,这里很重要!!!

      int midLeft=arr[mid]-arr[mid-1];

      int midRight=arr[mid+1]-arr[mid];

      //记录mid 附近两边的最小距离

      midLeft=midLeft>midRight?midRight:midLeft;

      int minLeft=minDistance(arr,left,mid);

      int minRight=minDistance(arr,mid+1,right);

      //记录mid 左侧和右侧的最小距离

      minLeft=minLeft>minRight?minRight:minLeft;

      //返回最小值

      return midLeft>minLeft?minLeft:midLeft;

    5、输出平面上距离最近的两个点的距离,给定一个点集,求出这个点集中最近两点的距离,这里需要进行一些排序操作,计算描述:

    a 按横坐标递增的形式对点集进行排序,相同的横坐标的点击再用纵坐标从小大大进行排序,然后切分点集,切分方法mid=(left+right)/2

    b 计算(left,mid)中的点集最小距离minleft,计算(mid,right)中的点集最小距离minright,此时mid-left<=3,right-mid<=3,如果

    mid-left>3,则继续对(left,mid)中的点集进行切分,(mid,right)同理

    c 计算mid+min(midleft,minright)之间的点击,按照遍历的方式进行计算

    伪代码描述:

    def minDis(point,left,right):

      if(left+1==right):

        //distance为预先定义好的计算方法

        return distance(point[left],point[right]);

      if(left+2==right):

        dis1=distance(point[left],point[left+1]);

        dis2=distance(point[left+1],point[right]);

        dis3=distance(point[left],point[right]);

        return min(dis1,min(dis2,dis3));

      mid=(left+right)/2;

      minleft=minDis(point,left,mid);

      minright=minDis(point,mid+1,right);

      //计算出mid点左右两侧中距离较短的点对距离

      minMid=min(minleft,minright);

      //以minMid为长度找出距离mid不超过minMid的点

      for i=left to right:

        if(Math.abs(point[mid].x-point[i])<d  && mid!=i):

          tempMemory.add(point[i]);

      for i=0 to tempMemory.length:

        for j=i+1 to tempMomory.length:

          minMid=min(minMid,distance(point[i],point[j]);

      return minMid;

    java代码示例:

       //这里未进行开方

      static int distance(List<Node> nodes,int left,int right){ Node leftNode=nodes.get(left),rightNode=nodes.get(right); int dis=(leftNode.x-rightNode.x)*(leftNode.x-rightNode.x)+ (leftNode.y-rightNode.y)*(leftNode.y-rightNode.y); return dis; } static int minDistance(List<Node> nodes,int left,int right){ if(right==left){ return Integer.MAX_VALUE; } if(right-1==left){ return distance(nodes,left,right); } if(right-2==left){ int m1=distance(nodes,left,left+1); int m2=distance(nodes,left+1,right); int m3=distance(nodes,left,right); return Math.min(m1,Math.min(m2,m3)); } int mid=(left+right)>>1; int leftmid=minDistance(nodes,left,mid); int rightmid=minDistance(nodes,mid+1,right); int minMid=Math.min(leftmid,rightmid); List<Node> temp=new ArrayList<>(); for(int i=left;i<right;i++){ if(Math.abs(nodes.get(i).x-nodes.get(mid).x)<minMid){ temp.add(nodes.get(i)); } } int dis=0; for(int i=0;i<temp.size();i++){ for(int j=i+1;j<temp.size();j++){ dis=distance(nodes,i,j); minMid=minMid>dis?dis:minMid; } } return minMid; }

    分治算法重要步骤:

    1、分解:大的问题进行互不相干的小问题

    2、解决:将小到一定规模的问题用简单的方法计算出结果

    3、合并:将小问题的解进行整合作为原始问题的解返给调用方

  • 相关阅读:
    |,&,<<,>>运算符
    Unity 异步加载场景
    string字母排序,
    冒泡算法
    Direct3D 12 编程---(1)
    点云密度粗估计
    git工具使用
    opencv---灰度图像与彩色图像遍历
    求平面两直线的交点,两直线段的交点
    结构体重载运算符
  • 原文地址:https://www.cnblogs.com/codeMedita/p/15315242.html
Copyright © 2011-2022 走看看