4

分而治之算法简介 - 数据结构和算法教程

 8 months ago
source link: https://www.jdon.com/71387.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

分而治之算法简介 - 数据结构和算法教程

在本文中,我们将讨论分而治之技术的作用以及如何使用 DAC 技术方法解决问题。在本节中,我们将讨论以下主题。 

  1. DAC简介。
  2. DAC技术下的算法。
  3. DAC算法的递归关系。
  4. 使用DAC技术的问题。

分而治之 
这种技术可以分为以下三个部分:

  • 划分:这涉及将问题划分为更小的子问题。
  • 征服:通过递归调用解决子问题,直至解决。
  • 组合:将子问题组合起来,得到整个问题的最终解决方案。

以下是遵循分而治之算法的一些标准算法。  

  • 快速排序是一种排序算法。该算法选择一个主元元素并重新排列数组元素,以便所有小于所选主元元素的元素都移动到主元的左侧,而所有大于的元素都移动到右侧。最后,算法对主元元素左右两侧的子数组进行递归排序。
  • 归并排序也是一种排序算法。该算法将数组分为两半,对它们进行递归排序,最后合并已排序的两半。
  • 最近的点对问题是在 xy 平面上的一组点中找到最近的点对。通过计算每对点的距离并比较距离以找到最小值,可以在 O(n^2) 时间内解决该问题。分而治之算法可以在 O(N log N) 时间内解决问题。
  • 施特拉森算法是一种有效的两个矩阵相乘算法。两个矩阵相乘的简单方法需要 3 个嵌套循环,时间复杂度为 O(n^3)。Strassen 的算法在 O(n^2.8974) 时间内将两个矩阵相乘。
  • Cooley-Tukey 快速傅立叶变换 (FFT) 算法是最常见的 FFT 算法。它是一种分而治之的算法,运行时间为 O(N log N)。
  • Karasuba 快速乘法算法最多可以完成两个n位数字的乘法

什么不符合分而治之的条件:
二分查找是一种搜索算法。在每个步骤中,算法都会将输入元素 x 与数组中中间元素的值进行比较。如果值匹配,则返回中间的索引。否则,如果 x 小于中间元素,则该算法针对中间元素的左侧递归,否则针对中间元素的右侧递归。

与普遍的看法相反,这不是分而治之的例子,因为每一步只有一个子问题(分而治之要求必须有两个或更多子问题),因此这是一种减少和解决的情况征服。

分而治之算法 :

DAC(a, i, j)
{
    if(small(a, i, j))
      return(Solution(a, i, j))
    else 
      mid = divide(a, i, j)               // f1(n)
      b = DAC(a, i, mid)                 // T(n/2)
      c = DAC(a, mid+1, j)            // T(n/2)
      d = combine(b, c)                 // f2(n)
   return(d)
}

DAC 算法的递归关系: 这是上述程序的递归关系。 

           O(1) if n is small
T(n) =     f1(n) + 2T(n/2) + f2(n)

示例: 
查找给定数组中的最大和最小元素。 
输入: { 70, 250, 50, 80, 140, 12, 14 }
输出:给定数组中的最小数字为:12
给定数组中的最大数字为:250

方法:从给定数组中查找最大和最小元素是分而治之的应用。在这个问题中,我们将找到给定数组中的最大和最小元素。在这个问题中,我们使用分而治之的方法(DAC),它具有分治、分治和组合三个步骤。

对于最大值: 
在这个问题中,我们使用递归方法来查找最大值,我们将看到只剩下两个元素,然后我们可以轻松使用条件,即 if(a[index]>a[index+1].)
在程序行中,a[index]和a[index+1])条件将确保左侧只有两个元素。

if(index >= l-2) 

if(a[index]>a[index+1]) 

// (a[index] 
// 现在,我们可以说最后一个元素将是给定数组中的最大值. 

else 

//(a[index+1] 
// 现在,我们可以说最后一个元素将是给定数组中的最大值。 
}
}

在上述条件中,我们检查了左侧条件以找出最大值。现在,我们将看到右侧条件来找到最大值。 
用于检查数组当前索引右侧的递归函数。

max = DAC_Max(a, 索引+1, l); 
// 递归调用

现在,我们将比较条件并检查给定数组当前索引处的右侧。 
在给定的程序中,我们将实现此逻辑来检查当前索引右侧的条件。

// 右边的元素将是最大的。 
if(a[index]>max) 
返回 a[index];
// max 将是给定数组中的最大元素。 
否则 
返回最大值; 

对于最小值: 
在这个问题中,我们将实现递归方法来找到最小值。在给定的数组中。 

int DAC_Min(int a, int index, int l) 
//递归调用函数求最小值。在给定的数组中。
if(index >= l-2) 
// 检查左侧是否有两个元素, 
然后我们可以轻松找到给定数组中的最小元素。 

// 这里我们将检查条件 
if(a[index]<a[index+1]) 
return a[index]; 
否则 
返回a[索引+1]; 
}

现在,我们将检查给定数组右侧的条件。 

// 递归调用给定数组的右侧。 
min = DAC_Min(a, 索引+1, l); 

现在,我们将检查条件以找到右侧的最小值。

// 右侧元素为最小值 
if(a[index]<min) 
return a[index]; 
// 这里 min 将是给定数组中的最小值。 
否则 
返回min ; 

Java代码

// 演示除法和
//征服算法的 Java 代码
class GFG{

// 函数用于查找给定数组中的最大数
//。
static int DAC_Max(int a, int index, int l)
{
    int max;
    if(l - 1 == 0)
    {
    return a[index];
    }
    if (index >= l - 2) 
    {
        if (a[index] > a[index + 1])
            return a[index];
        else
            return a[index + 1];
    }

// 在给定数组中查找最大元素的逻辑
    //。
    max = DAC_Max(a, index + 1, l);

if (a[index] > max)
        return a[index];
    else
        return max;
}

// 函数用于查找给定数组中的最小数
//。
static int DAC_Min(int a, int index, int l)
{
    int min;
    if(l - 1 == 0)
    {
    return a[index];
    }
    if (index >= l - 2)
    {
        if (a[index] < a[index + 1])
            return a[index];
        else
            return a[index + 1];
    }

// 在给定数组中查找最小元素
    // 的逻辑。
    min = DAC_Min(a, index + 1, l);

if (a[index] < min)
        return a[index];
    else
        return min;
}

// Driver Code
public static void main(String args)
{

// Defining the variables
    int min, max;

// Initializing the array
    int a = { 70, 250, 50, 80, 140, 12, 14 };

// Recursion - DAC_Max function called
    max = DAC_Max(a, 0, 7);

// Recursion - DAC_Max function called
    min = DAC_Min(a, 0, 7);

System.out.printf("The minimum number in " +
                    "a given array is : %d\n", min);
    System.out.printf("The maximum number in " +
                    "a given array is : %d", max);
}
}

Python代码

# Python3 code to demonstrate Divide and
# Conquer Algorithm

# Function to find the maximum no.
# in a given array.


def DAC_Max(a, index, l):
    max = -1
    if(l - 1 == 0):
        return arr[index]
    if (index >= l - 2):
        if (a[index] > a[index + 1]):
            return a[index]
        else:
            return a[index + 1]

# Logic to find the Maximum element
    # in the given array.
    max = DAC_Max(a, index + 1, l)

if (a[index] > max):
        return a[index]
    else:
        return max

# Function to find the minimum no.
# in a given array.


def DAC_Min(a, index, l):
    min = 0
    if(l - 1 == 0):
        return arr[index]
    if (index >= l - 2):
        if (a[index] < a[index + 1]):
            return a[index]
        else:
            return a[index + 1]

# Logic to find the Minimum element
    # in the given array.
    min = DAC_Min(a, index + 1, l)

if (a[index] < min):
        return a[index]
    else:
        return min


# Driver Code
if __name__ == '__main__':

# Defining the variables
    min, max = 0, -1

# Initializing the array
    a = [70, 250, 50, 80, 140, 12, 14]

# Recursion - DAC_Max function called
    max = DAC_Max(a, 0, 7)

# Recursion - DAC_Max function called
    min = DAC_Min(a, 0, 7)
    print("The minimum number in a given array is : ", min)
    print("The maximum number in a given array is : ", max)

Java中用Fork-Join查找给定数组中的最大和最小元素

在Java中,可以使用Fork-Join框架来并行地查找给定数组中的最大和最小元素。Fork-Join框架提供了一种方便的方式来执行递归任务,并通过分治的方式将任务拆分成子任务,从而实现并行计算。

以下是一个使用Fork-Join框架查找数组中最大和最小元素的示例代码:

import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;

public class MaxMinFinder extends RecursiveTask<MinMaxResult> {
    private static final int THRESHOLD = 500; // 阈值,控制任务拆分的大小
    private int array;
    private int start;
    private int end;

public MaxMinFinder(int array, int start, int end) {
        this.array = array;
        this.start = start;
        this.end = end;
    }

@Override
    protected MinMaxResult compute() {
        int length = end - start + 1;

if (length <= THRESHOLD) {
            // 如果任务足够小,直接计算最大和最小值
            int min = array[start];
            int max = array[start];
            for (int i = start + 1; i <= end; i++) {
                if (array[i] [/i]< min) {
                    min = array;
                }
                if (array > max) {
                    max = array;
                }
            }
            return new MinMaxResult(min, max);
        } else {
            // 如果任务太大,拆分为两个子任务并递归地执行
            int mid = start + (end - start) / 2;
            MaxMinFinder leftTask = new MaxMinFinder(array, start, mid);
            MaxMinFinder rightTask = new MaxMinFinder(array, mid + 1, end);

// 并行执行子任务
            invokeAll(leftTask, rightTask);

// 合并子任务的结果
            MinMaxResult leftResult = leftTask.join();
            MinMaxResult rightResult = rightTask.join();

// 合并最小和最大值
            int min = Math.min(leftResult.getMin(), rightResult.getMin());
            int max = Math.max(leftResult.getMax(), rightResult.getMax());

return new MinMaxResult(min, max);
        }
    }

public static void main(String args) {
        int array = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};

ForkJoinPool forkJoinPool = new ForkJoinPool();
        MaxMinFinder task = new MaxMinFinder(array, 0, array.length - 1);
        MinMaxResult result = forkJoinPool.invoke(task);

System.out.println("Min: " + result.getMin());
        System.out.println("Max: " + result.getMax());
    }
}

class MinMaxResult {
    private final int min;
    private final int max;

public MinMaxResult(int min, int max) {
        this.min = min;
        this.max = max;
    }

public int getMin() {
        return min;
    }

public int getMax() {
        return max;
    }
}

在这个示例中,MaxMinFinder类是一个RecursiveTask,它负责查找数组中的最大和最小值。在compute方法中,如果任务足够小(小于等于阈值),则直接计算最大和最小值;否则,将任务拆分为两个子任务,并通过invokeAll并行执行这两个子任务。然后,通过join方法等待子任务完成并获取其结果,最终合并子任务的结果得到整体的最小和最大值。在main方法中,创建一个ForkJoinPool实例,并通过invoke方法启动任务并获取结果。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK