首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >常见算法设计方法-分治法

常见算法设计方法-分治法

作者头像
潘成涛
发布2018-01-18 11:53:47
6610
发布2018-01-18 11:53:47
举报
文章被收录于专栏:程序员与猫程序员与猫

分治法(Devide & Conquer)

1. 常见步骤

  • Devide 把一个问题的特殊实例划分成若干个子问题
  • Conquer 递归地解决每个子问题
  • Combine 将每个子问题的答案组合成最终答案

2. 举例分析

归并排序就是常见的一种采用“分治法”进行设计的算法,以下先给出具体的C#版代码示例

    /// <summary>
    ///     对列表进行递归排序
    /// </summary>
    /// <param name="list">待排序数组</param>
    /// <returns></returns>
    public static List<int> Sort(List<int> list)
    {
        if (list.Count <= 1)
            return list;
        var mid = list.Count/2;
        var left = new List<int>(); 
        var right = new List<int>(); 
        
        // Devide
        for (var i = 0; i < mid; i++)
            left.Add(list[i]);
        for (var j = mid; j < list.Count; j++)
            right.Add(list[j]);
        // Conquer
        left = Sort(left);
        right = Sort(right);

        // Combine
        return Merge(left, right);
    }

    /// <summary>
    ///     合并已经排序好的两个List
    /// </summary>
    /// <param name="left">Left List</param>
    /// <param name="right">Right List</param>
    /// <returns></returns>
    private static List<int> Merge(List<int> left, List<int> right)
    {
        var temp = new List<int>();
        while ((left.Count > 0) && (right.Count > 0))
        {
            if (left[0] <= right[0])
            {
                temp.Add(left[0]);
                left.RemoveAt(0);
            }
            else
            {
                temp.Add(right[0]);
                right.RemoveAt(0);
            }
        }

        if (left.Count > 0)
        {
            foreach (int item in left)
            {
                temp.Add(item);
            }
        }
            
        if (right.Count > 0)
        {
            foreach (int item in right)
            {
                temp.Add(item);
            }
        }
        
        return temp;

    }

分析这个算法可以发现,归并算法的递归部分在于不断地将待排序数组分为左右两个等长的数组直至左右列表中都只含有一个元素,再继续进行Merge操作,前者递归所花费的时间可以简单表示成2T(n/2),后者排序可以认为是θ(n),则总时间可以表示成T(n)=2T(n/2)+θ(n)。

平均情况下,定义的T(n)=输入规模为n之下时所有可能输入的期望时间,θ是渐进符号一种,大家可以简单认为对于输入n,f(n)存在精确上下界

接下来在计算时间复杂度的时候,针对这个优雅的时间函数我们可以有两种解决办法,第一种是判断整个递归树的长度和叶节点的个数,第二种则是直接套用主定理公式进行分析。这里我们采用第二种主定理进行分析。

这里是对主定理的相关说明

针对T(n)=aT(n/b)+f(n)的函数式子(a≥1,b>1),我们可以知道归并排序算法的函数符合主定理的第二种情况,即如果存在常数k ≥ 0,有 f(n)=θ(n^(㏒{b}a((㏒n)^k)),则有T(n)=θ(n^(㏒{b}a((㏒n)^(k+1)))。这里的k=0,则归并算法最终的时间复杂度T(n)=θ(n㏒n)

额外补充一个二分法实例

    /// <summary>
    ///     二分法查找
    /// </summary>
    /// <param name="list">传入的有序列表</param>
    /// <param name="beginIndex">起始位置</param>
    /// <param name="endIndex">终止位置</param>
    /// <param name="x">需要查找的x</param>
    /// <returns>返回的列表索引</returns>
    public static int BinarySearch(List<int> list, int beginIndex, int endIndex, int x)
    {
        if ((x > list.LastOrDefault()) | (x < list.FirstOrDefault()))
            return -1;

        if (x == list[beginIndex])
            return beginIndex;

        if (x == list[endIndex])
            return endIndex;

        var mid = (beginIndex + endIndex)/2;
        if (x == list[mid])
            return mid;
        return x > list[mid] ? BinarySearch(list, mid, endIndex, x) : BinarySearch(list, beginIndex, mid, x);

    }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-10-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 分治法(Devide & Conquer)
    • 1. 常见步骤
      • 2. 举例分析
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档