数字排列组合是个经典的算法问题,它很通俗易懂,适合不懂业务的人学习,我们通过它来发现和运用并行计算的优势,可以得到一个很直观的体会,并留下深刻的印象。问题如下: 请写一个程序,输入M,然后打印出M个数字的所有排列组合(每个数字为1,2,3,4中的一个)。比如:M=3,输出: 1,1,1 1,1,2 …… 4,4,4 共64个 注意:这里是使用计算机遍历出所有排列组合,而不是求总数,如果只求总数,可以直接利用数学公式进行计算了。 这种算法常用递归或迭代来实现,单当M=14时,中间结果数量已经过亿,再大的话很容易超过单台机器的处理能力,所以我用hadoop来实现多机分别处理。 ### 基于Hadoop用并行递归实现排列组合运算 #### 背景介绍与问题描述 在计算机科学领域,数字排列组合是经典的算法问题之一,它不仅通俗易懂,而且对于初学者来说非常友好。通过这个问题的学习,我们可以很好地理解和应用并行计算的概念和技术。本篇文章将介绍如何使用Hadoop框架来实现一个并行递归算法,用于生成给定长度的所有可能的排列组合。 问题的具体描述如下:给定一个整数`M`,程序需要输出由数字`1`、`2`、`3`、`4`组成的长度为`M`的所有排列组合。例如,当`M=3`时,输出如下: ``` 1,1,1 1,1,2 ... 4,4,4 ``` 共有64种不同的排列组合。需要注意的是,这里的任务不仅仅是计算这些排列组合的数量,而是要具体生成并打印出每一种排列组合。 #### 递归算法简介 递归是一种重要的编程思想,在许多算法设计中都有广泛的应用。在解决排列组合问题时,递归算法能够清晰地表达问题的结构。然而,随着`M`值的增大,单机计算所有排列组合变得越来越困难,因为中间结果的数量会迅速增长。例如,当`M=14`时,中间结果的数量就已经超过了1亿,这很容易超出单台机器的处理能力。 #### Hadoop与并行计算 Hadoop是一个开源的大数据处理框架,它支持分布式存储和并行处理。通过使用Hadoop MapReduce框架,我们可以将任务分解成多个子任务,在多台机器上并行执行。这种方法非常适合处理大规模的数据集,特别是在处理排列组合这样的问题时,可以通过将任务分散到不同的节点上来加速计算过程。 #### 实现方案 为了实现基于Hadoop的并行递归算法,我们需要编写MapReduce作业。具体的实现步骤如下: 1. **定义Mapper类**:Mapper类的主要任务是负责生成初始的排列组合元素。在本例中,Mapper需要根据输入的`M`值生成初始的数字序列,并将它们作为键值对输出。 2. **定义Reducer类**:Reducer类的作用是接收来自Mapper的输出,并对这些输出进行进一步的组合处理,生成更长的排列组合序列。Reducer需要递归地调用自身来生成所有可能的组合。 3. **配置Job**:配置MapReduce作业的相关参数,包括输入格式、输出格式、Mapper类、Reducer类等。 4. **运行作业**:提交作业并在Hadoop集群上运行。 #### 代码解析 在给定的部分代码中,我们看到了一个名为`Recursion2`的类,该类继承自`Configured`并实现了`Tool`接口。这个类包含了`main`方法和`run`方法,其中`run`方法负责设置和启动MapReduce作业。 - **Mapper类** (`RecMapper`):该类负责生成初始的排列组合元素。在这个例子中,我们假设`n`为可选数字的范围(即1到4),`m`为需要生成的排列组合的长度。Mapper类的实现中应该包含递归逻辑,以便生成所有可能的序列。 - **Reducer类** (`RecReducer`):Reducer类的作用是接收来自Mapper的输出,并对这些输出进行进一步的组合处理。Reducer也需要包含递归逻辑来确保所有可能的排列组合都被正确地生成。 #### 结论 通过对上述问题的研究,我们可以看到并行计算的强大之处。通过Hadoop框架,我们可以有效地处理大规模数据集,从而大大提高了计算效率。在实际应用中,这种方法不仅可以应用于排列组合问题,还可以扩展到其他许多需要大量计算资源的问题场景中。
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.InputFormat;
import org.apache.hadoop.mapreduce.InputSplit;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.JobContext;
import org.apache.hadoop.mapreduce.MapContext;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.OutputCommitter;
import org.apache.hadoop.mapreduce.RecordReader;
import org.apache.hadoop.mapreduce.RecordWriter;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.StatusReporter;
import org.apache.hadoop.mapreduce.TaskAttemptContext;
import org.apache.hadoop.mapreduce.TaskAttemptID;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
public class Recursion2 extends Configured implements Tool {
public static void main(String[] args) throws Exception {
int res = ToolRunner.run(new Recursion2(), args);
System.exit(res);
}
public int run(String[] args) throws Exception {
if (args.length == 0) {
System.out.println("Usage: writer <out-dir>");
ToolRunner.printGenericCommandUsage(System.out);
return -1;
}
Path path = new Path(args[0]);
Job job = new Job(getConf(),"three-Recursion");
job.setJarByClass(Recursion2.class);
job.setInputFormatClass(VirtualInputFormat.class);
job.setOutputFormatClass(TextOutputFormat.class);
TextOutputFormat.setOutputPath(job, path);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.setMapperClass(RecMapper.class);
job.setReducerClass(RecReducer.class);
job.setNumReduceTasks(1);
剩余5页未读,继续阅读
- 强手james2016-03-21还可以,不过需要进一步修改
- 粉丝: 1
- 资源: 6
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助