zoukankan      html  css  js  c++  java
  • 3*n/2

    求区间范围最小值最大值  
      用分治法(Divide and Conquer)求n元数组最小元与最大元,当n=1时,不用比较,最大元和最小元都是这个数;当n=2时,一次比较就可以找出两个数据元素的最大元和最小元;当n>2时,可以把n个数据元素分为大致相等的两半,一半有n/2个数据元素,而另一半有n/2个数据元素。先分别找出各自组中的最大元和最小元,然后将两个最大元进行比较,就可得n个元素的最大元;将两个最小元进行比较,就可得n个元素的最小元。

      在规模为n的数据元素集合中找出最大元和最小元, 至少需要3n/2-2次比较,即3n/2-2是找最大最小元算法的下界。当n=2k,或当n≠2k时,若n是若干2的整数幂之和,则算法的时间复杂度仍可达到下界3n/2-2。

    a.为一个分治算法编写伪代码,该算法同时求出一个n元数组的最大元素和最小元素的值。
    b.请拿该算法与解同样问题的蛮力算法做一个比较。

    解答:
    a.同时求出最大值和最小值,只需要将原数组一分为二,再使用相同的方法找出这两个部分中的最大值和最小值,然后经过比较就可以得到整个问题的最大值和最小值。

    算法 minmax_element(A[l..r], min, max)
    // 该算法利用分治技术得到数组A中的最大值和最小值
    // 输入:数值数组A[l..r]
    // 输出:最小值min和最大值max

    if(r<0) return;      // 空数组,没有最大最小元
    if(r==0) max=min=A[0]; // 只有一个元素时
    if(r==1) {min=A[0]<=A[1]?A[0]:A[1]; max=A[0]<=A[1]?A[1]:A[0];}  // 有两元素时
    else
    {  
      m=int((l+r)/2);   // 去中间值,把数组分成两个部分
      minmax_element(l, m, fMin, fMax);   // 递归解决前一部分
      minmax_element(m+1, r, sMin, sMax); // 递归解决后一部分
      max= std::max(fMax, sMax); // 从两部分的两个最大值中选择大值
      min= std::min(fMin, sMin); // 从两部分的两个最小值中选择小值
    }

    为了数据类型一般话,我们采用 C++ 的模板。将最小最大数对存储在 std::pair 类型中。

    template<class ForwardIt, class Compare>
    std::pair<ForwardIt, ForwardIt> minmax_element(ForwardIt first, ForwardIt last, Compare comp)
    {
        std::pair<ForwardIt, ForwardIt> result(first, first);
    
        if(first == last) return result;
        if(++first == last) return result;
    
        if(comp(*first, *result.first))
            result.first = first;
        else
            result.second = first;
    
        while(++first != last)
        {
            ForwardIt i = first;
            if(++first == last)
            {
                if(comp(*i, *result.first))
                    result.first = i;
                else if (!(comp(*i, *result.second)))
                    result.second = i;
                break;
            }
            else
            {
                if(comp(*first, *i))
                {
                    if(comp(*first, *result.first))
                        result.first = first;
                    if(!(comp(*i, *result.second)))
                        result.second = i;
                }
                else
                {
                    if(comp(*i, *result.first))
                        result.first = i;
                    if(!(comp(*first, *result.second)))
                        result.second = first;
                }
            }
        }
        return result;
    }

    时间复杂度为:
    t(n)=2*t(n/2)+2 n>2
    t(1)=0 t(2)=1
    设n=2^k,则n/2=2^(k-1)
    t(n)=t(2^k)=2*t[2^(k-1)]+2
    =2[2*t(2^(k-2))+2]+2
    =2^2*t[2^(k-2))]+2^2+2
    =2^2[2*t[2^(k-3)]+2]+2^2+2
    =2^3*t[2^(k-3)]+2^3+2^2+2
    =...
    =2^(k-1)*t(2)+2^(k-1)+2^(k-2)+...+2   // t(2)=1
    =2^(k-1)+2^(k-1)+2^(k-2)+...+2 // 后面部分为等比数列求和
    =2^(k-1)+2^k-2    // 2^(k-1)=n/2, 2^k=n
    =n/2+n-2
    =3*n/2-2

    b.蛮力法的算法如下:

    算法 simple_minmax(A[0..n])
    // 用蛮力法得到数组A的最大值和最小值
    // 输入:数值数组A[l..r]
    // 输出:最小值min和最大值max

    max=min=A[0];
    for(i=0; i<n; ++i)
    {
      if(A[i]>max) max=A[i];
      if(A[i]<min) min=A[i];
    }

    蛮力算法的时间复杂度t(n)=2*(n-1)

    C++ 的头文件 <algorithm>包含了上面两种算法。
    3*n/2-2 对应 std::minmax_element
    2*(n-1) 对应 std::min_element + std::max_element


    算法 minmax_element 的时间复杂度为3*n/2-2,simple_minmax 的时间复杂度为2n-2,都属于Θ(n)复杂度。
    但比较可得,minmax_element 减少了不必要的比较
    速度上比 simple_minmax 的快一些。

  • 相关阅读:
    SVN Monitor工具推荐
    Linux Netbeans汉化不全
    PMWiki安装教程
    JIRA重启服务器后需要重启TOMCAT的解决
    SVN分支与合并
    WCF无法捕获FaultException
    非完美C++ Singleton实现[转载]
    C语言结构体的对齐原则
    C++ STL 学习笔记
    字符串笔试题
  • 原文地址:https://www.cnblogs.com/Martinium/p/minmax_element.html
Copyright © 2011-2022 走看看