数据结构与算法笔记:基础篇 - 分治算法:谈一谈大规模计算框架MapReduce中的分治思想

概述

MapReduce 是 Google 大数据处理的三姐马车之一,另外两个事 GFS 和 Bigtable。它在倒排索引、PageRank 计算、网页分析等搜索引擎相关的技术中都有大量的应用。

尽管开发一个 MapReduce 看起来很高深。实际上,万变不离其宗,它的本质就是本章要学的这种算法思想,分支算法。


如何理解分支算法?

为什么说 MapReduce 的本质就是分治算法呢?先来看看什么事分治算法?

分治算法(divide and conquer)的核心思想其实就是四个字,分而治之,也就是将原问题划分成 n 个规模较小,并且结构与原问题相似的子问题,递归地解决这些子问题,然后再合并其结果,就得到原问题的解。

这个定义看起来有点类似递归地定义。关于分治和递归,我们在 排序(下) 的时候讲过,分治算法是一种处理问题的思想,递归是一种编程技巧。实际上,分治算法一般都比较适合用递归来实现。分治算法的递归实现中,每一次递归都会涉及三个操作:

  • 分解:将原问题分解为一系列子问题;
  • 解决:递归地求解各个子问题,若子问题足够小,则直接求解;
  • 合并:将子问题的结果合并成原问题。

分治算法能解决的问题,一般要满足以下几个条件:

  • 原问题与分解成的小问题具有相同的模式;
  • 原问题分解的子问题可以独立解决,子问题之间没有相关性,这一点是分治算法跟动态规划的明显区别,等讲到动态规划,会详细对比这两种算法;
  • 具有分解终止条件,也就是说,当问题足够小时,可以直接求解;
  • 可以将子问题合并成原问题,而这个合并操作的复杂度不能太高,否则就起不到减少算法总体复杂度的效果了。

分治算法应用举例分析

理解分治算法的原理并不难,但是要想灵活应用并不容易。所以,接下来,我会带你用分治算法解决我们在讲排序的时候设计的一个问题,加深你对分治算法的理解。

还记得我们在排序算法里讲到的数据的有序度、逆序度的概念吗?我当时讲到,我们用有序度表示一组数据的有序程度,用逆序度表示一组数据的无序程度。

假设我们有 n 哥数据,我们期望数据从小到大排列,那完全有序的数据的有序度就是 n(n-1)/2,逆序度等于 0;相反,倒序排列的数据的有序度就是 0,逆序度就是 n(n-1)/2。除了这两种极端情况外,我们通过计算有序对或逆序对的个数,来表述数据的有序度或逆序度。

在这里插入图片描述

现在的问题是,如何编码求出一组数据的有序对个数或者逆序对个数呢? 因为有序对个数和逆序对个数的求解方式是类似的,所以你可以之思考逆序对个数的求解方法。

最笨的方法是,拿每个数组跟它后面的数字比较,看看有几个比它小。我们把比它小的数字的个数记作 k,通过这样的方式,把每个数字都考察一遍之后,然后对每个数字对应的 k 值求和,最后得到的总和就是逆序对个数。不过,这样擦做的时间复杂度是 O ( n 2 ) O(n^2) O(n2)。有没有更加高效的处理方法呢?

我们用分治法来试试。我们套用分治法的思想来求数组 A 的逆序对个数。我们可以将数组分成前后两半 A1 和 A2,分别计算 A1 和 A2 之间的逆序对个数 K1 和 K2,然后再计算 A1 和 A2 之间逆序对个数 K3。那数组 A 的逆序对个数就等于 K1+K2+K3。

我们前面讲过,使用分治算法其中一个要求是,子问题合并的代价不能太大,否则就起不到了降低时间复杂度的效果了。那回到这个问题,如何快速计算出两个子问题 A1 与 A2 之间的逆序对个数呢?

这里就要借助归并排序算法了。你可以先试着想想,如何借助归并排序算法来解决呢?

归并排序中有一个非常关键的操作,就是将两个有序的小数组,合并成一个有序的数组。实际上,在这个合并的过程中,我们就可以计算这连个小数组的逆序对个数了。每次合并操作,我们都计算逆序对个数,把这些计算出来的逆序对个数求和,就是这个数组的逆序对个数了。

在这里插入图片描述

尽管画了张图来解释,但个人觉得,对于工程师来说,看代码更好理解一些,所以我们把这个过程翻译成了代码,你可以结合着图和文字描述一起看下。

    private int num = 0; // 全局变量或成员变量

    public int count(int[] a, int n) {
        num = 0;
        mergeSortCounting(a, 0, n-1);
        return num;
    }

    private void mergeSortCounting(int[] a, int p, int r) {
        if (p >= r) return;
        int q = (p + r) / 2;
        mergeSortCounting(a, p, q);
        mergeSortCounting(a, q+1, r);
        merge(a, p, q, r);
    }

    private void merge(int[] a, int p, int q, int r) {
        int i = p, j = q+1, k = 0;
        int[] tmp = new int[r-p+1];
        while (i <= q && j <= r) {
            if (a[i] < a[j]) {
                tmp[k++] = a[i++];
            } else {
                num += (q-i+1); // 统计p~q之间比a[j]大的元素的个数
                tmp[k++] = a[i++];
            }
        }
        while (i <= q) { // 处理剩下的
            tmp[k++] = a[i++];
        }
        while (j <= r) { // 处理剩下的
            tmp[k++] = a[j++];
        }
        for (i = 0; i <= r-p; i++) { // 从tmp拷贝回a
            a[p+i] = tmp[i];
        }
    }

很多同学经常会说,某某算法思想如此巧妙,我是怎么也想不到的。实际上,确实是的。有些算法确实非常巧妙,并不是每个人短时间都能想到的。比如这个问题,并不是每个人都能想到可以借助归并排序算法来解决。不夸张地说,如果之前没接触过,觉得部分人都想不到。但是,如果我告诉你可以借助归并排序算法来解决,那你就应该想到如何改造归并排序,来求解这个问题了,只要你能做到这一点,我觉得就很棒了。

关于分治算法,还有两道比较经典的问题:

  • 二维平面上有 n 个点,如何快速计算出两个距离最近的点对?
  • 有两个 nn 的矩阵 A,B,如何快速求解两个矩阵的成绩 C=AB?

分治思想在海量数据处理中的应用

分治算法思想的应用是非常广发的,并不仅限于指导编程和算法设计。它还经常用在海量数据处理的场景中。我们前面讲的数据结构和算法,大部分都是基于内存存储和单机处理。但是,如果要处理的数据量非常大,没法一次性放到内存中,这个时候,这些数据结构和算法就无法工作了。

比如,给 10GB 订单文件按照金额排序这样一个需求,看似是一个很简单的排序问题,但是因为数据量大,有 10GB,而我们机器的内存可能只有 2、3GB 这样子,无法一次性加载到内存,也就无法通过单纯地使用快排、归并排序等基础算法来解决了。

要解决这种数据量大到内存装不下的问题,我们就可以利用分治的思想。我们可以将海量的数据集合根据某种方法,划分为几个小的数据集合,每个小的数据集合单独加载到内存来解决,然后再将小数据集合合并成大数据集合。实际上,利用这种分治的处理思路,不仅仅能克服内存的限制,还能利用多线程或者多机处理,加快处理的速度。

比如刚刚的例子,给 10GB 的订单排序,我们可以先扫描一遍订单,根据订单的金额,将 10GB 的文件划分为几个金额区间。比如订单金额 1 到 100 元的放到一个小文件,101 到 200 的放到另一个文件,以此类推。这样每个小文件都可以单独加载到内存排序,最后将这些有序的小文件合并,就是最终有序的 10GB 订单数据了。

如果订单存储在类似 GFS 这样的分布式系统上,当 10GB 订单被划分成多个小文件的时候,每个文件可以并行加载到多态机器上处理,最后再将结果合并在一起,这样并行处理的速度也加快了很多。不过,这里有一点要注意,就是数据的存储与计算所在的机器是同一个或在网络中靠的很近(比如一个局域网内,数据存取速度很快),否则就会因为数据访问的速度,导致整个处理过程不但不会变快,反而有可能变慢。

你可能还有印象,这个就是我们在讲线性排序的时候举的例子。实际上,在前面已经学习的课程中,还讲了很多利用分治算法来解决的问题。

谈一谈大规模计算框架MapReduce中的分治思想

刚刚举的订单的例子,数据有 10GB 大小,可能给你的感受还不强烈。那如果我们要处理的数据时 1T、10T、100T 这样的数据,那一台机器处理的效率肯定是非常低的。而对于谷歌搜索引擎来说,网页爬取、清洗、分析、分词、计算权重、倒排索引等等各个环节中,都会面对如此海量的数据(比如网页)。所以利用集群并行处理显然是大势所趋。

一台机器过于低效,那我们就把人去拆分到多态机器上来处理。如果拆分之后的小人物之间互不干扰,独立计算,最后再将结果合并。这不就是分治思想吗?

实际上,MapReduce 框架只是一个任务调度器,底层依赖 GFS 来存储数据,依赖 Borg 管理机器。它从 GFS 中拿数据,交给 Brog 中的机器执行,并且时刻监控机器执行的进度,一旦机器出现宕机、进度卡壳等,就重新从 Brog 中调度一台机器执行。

尽管 MapReduce 的模型非常简单,但是在 Google 内部应用非常广泛。它除了可以用来处理这种数据与数据之间存在关系的任务,比如 MapReduce 的经典例子,统计文件中单词出现的频率。此外,它还可以用来处理数据与数据之间没有关系的任务,比如对网页分析、分词等,每个网页可独立的分析、分词,而这两个网页之间没有关系。网页几十亿、上百亿,如果单机处理,效率地下,我们就可以利用 MapReduce 提供可靠、高性能、高容错的并行计算框架,并行地处理这几十亿、上百亿的网页。

小结

本章讲了一种应用非常广泛的算法思想,分治算法。

分治算法用四个字概况就是 “分而治之”,将原问题划分成几个规模较小而结构与原问题相似的子问题,递归地解决这些子问题,然后再合并其结果,就得到原问题的解。这个思想非常简单、好理解。

本章讲解了两种分治算法的经典的应用场景,一个是用来指导编码,降低问题求解的时间复杂度,另一个是解决海量数据处理问题。比如 MapReduce 本质上就是利用了分治思想。

我们也时常感叹 Google 的创新能力如此之强,总是在引领技术的发展。实际上,创新并非离我们很远,创新的源泉来自对事物本质的认识。无数优秀架构设计的思想来源都是基础的数据结构和算法,这本身就是算法的一个魅力所在。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/726072.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

three.js 基础01

目录 1.场景创建 Scene() 2.常用形状集几何体「Geometry」[可设置长宽高等内容&#xff0c;如&#xff1a;new THREE.BoxGeometry(...)] 3.常用材质「Material」[可设置颜色等内容&#xff0c;如&#xff1a;new THREE.MeshBasicMaterial({})] 4.添加、定位 5.相机api 6…

1-函数极限与连续

1 2 平方项没有考虑到&#xff08;其正负&#xff09;

Linux下更新curl版本

一、前景 由于低版本的curl存在一定的漏洞&#xff0c;会对我们的服务器安全造成问题&#xff0c;所以&#xff0c;我们需要将curl由低版本安装到高版本。 二、步骤 1、首先检测服务器安装的curl版本 curl --version 2、查看服务器安装的curl的安装包 rpm -qa curl 3、卸载旧…

LLM上下文长度扩展方案:NTK-aware interpolation

文章目录 1. Position Interpolation存在的问题高频信息损失 NTK-aware Scaled RoPE&#xff1a;高频外推低频内插进制编码代码实现 1. Position Interpolation存在的问题 在之前的一篇文章中讲了位置内插方案&#xff1a;LLM上下文长度扩展方案&#xff1a;Position Interpol…

【计算机网络篇】数据链路层(11)在数据链路层扩展以太网

文章目录 &#x1f354;使用网桥在数据链路层扩展以太网&#x1f95a;网桥的主要结构和基本工作原理&#x1f388;网桥的主要结构&#x1f50e;网桥转发帧的例子&#x1f50e;网桥丢弃帧的例子&#x1f50e;网桥转发广播帧的例子 &#x1f95a;透明网桥&#x1f50e;透明网桥的…

二开的精美UI站长源码分享论坛网站源码 可切换皮肤界面

二开的精美UI站长源码分享论坛网站源码 可切换皮肤界面 二开的精美UI站长源码分享论坛网站源码 可切换皮肤界面

c# winform修改控件数字类型运行输入null

txtMaxQty.Properties.Mask.MaskTypeDevExpress.XtraEditors.Mask.MaskType.Numeric; txtUrgentQty.Properties.Mask.MaskTypeDevExpress.XtraEditors.Mask.MaskType.Numeric;txtMinQty.Properties.Mask.MaskType DevExpress.XtraEditors.Mask.MaskType.Numeric;在winform里&am…

openh264 码率控制原理框架

openh264 OpenH264 是一个开源的 H.264 视频编码库&#xff0c;由 Cisco Systems, Inc. 开发并提供。它支持 H.264 的主要编码特性&#xff0c;包括但不限于&#xff1a; 支持基线、主要、高和高10配置文件支持帧内预测、帧间预测、变换编码、量化、环路滤波等支持多线程编码支…

Nvidia Isaac Sim 入门教程 2024(3)图形界面

Isaac Sim 基本使用 版权信息 Copyright 2023-2024 Herman YeAuromix. All rights reserved.This course and all of its associated content, including but not limited to text, images, videos, and any other materials, are protected by copyright law. The author …

Hadoop3:MapReduce中的Partition原理及自定义Partition

一、默认Partition分区配置 以WC案例来进行验证。 1、设置setNumReduceTasks 修改的代码 这行代码&#xff0c;确定了reduceTask的数量&#xff0c;也确定了分区逻辑 在mapper文件中&#xff0c;打上断点 计算分区的代码 这里会对每一个kv进行计算&#xff0c;然后&#…

【星环社区版TDH2024年度大事件】全新版本?全新组件?性能提升10倍?

TDH社区版家族迎来新成员 不知不觉社区版已经陪伴大家将近两年的时间了&#xff0c;在这两年里收获到了很多认可&#xff0c;同时也收获到了一些建议与意见&#xff0c;比如资源成本的问题。在去年我们发布了TDH社区开发版&#xff0c;仅需单台服务器即可一键安装部署Inceptor…

zip文件上传到linux服务器文件大小发生变化

在传一个文件到服务器的时候&#xff0c;第一次传完看见大小不一样&#xff08;服务器中du命令查看大小796596MB&#xff09;就重传了一下&#xff0c;还是大小不一样&#xff0c;就查了下。 查了下有以下原因&#xff1a; 文件系统的不同&#xff1a; 原因&#xff1a;不同的…

12.2 Go 编写测试代码

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

Spring之IoC(容器配置、Spring坐标导入、获取bean)

这里的话&#xff0c;因为博主学习时间有限&#xff0c;并没有实际去操作&#xff0c;只是学习和了解一个大概的流程。 目录 一、引言 1、管理什么&#xff1f;&#xff08;对象&#xff1a;Service、Dao ...&#xff09; 2、如何将被管理的对象告知 IoC 容器?&#xff08;用…

Linux内核编程(六)平台总线plantform驱动模型

本文目录 前述&#xff1a;为什么引入平台总线模型一、知识点1. 什么是平台总线模型2. 平台总线模型使用3. 平台总线是如何工作的4. 平台总线模型的优点 二、平台总线设备层1. 常用API&#xff08;1&#xff09; 注册一个平台设备&#xff08;2&#xff09; 注销一个平台设备&a…

2748. 美丽下标对的数目

题目 给定一个下标从 0 开始的整数数组 nums。如果下标对 (i, j) 满足 0 ≤ i < j < nums.length&#xff0c;且 nums[i] 的第一个数字与 nums[j] 的最后一个数字互质&#xff0c;那么认为 nums[i] 和 nums[j] 是一组美丽下标对。 对于两个整数 x 和 y&#xff0c;如果…

无忧易售新功能:集成图片库智能图片翻译,跨越语言障碍

在电商全球化的浪潮中&#xff0c;跨越语言的障碍&#xff0c;让产品图像说话&#xff0c;成为了商家致胜的关键。"无忧易售ERP"推出集成图片库与图片翻译功能的全新升级&#xff0c;为全球电商提供一站式解决方案&#xff0c;让商品跨越国界&#xff0c;沟通无界。 …

使用二进制安装安装docker

在一些情况下无法使用yum安装docker下面写了一个使用二进制安装docker的文档 官网下载地址https://download.docker.com/linux/static/stable/x86_64/ 可以按需求下载 wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.10.tgz 下载包 tar xf dcker…

计算机网络 —— 应用层(DHCP)

计算机网络 —— 应用层&#xff08;DHCP&#xff09; 什么是DHCPDHCP工作过程DHCP DISCOVERDHCP OFFERDHCP RQUESTDHCP ACK DHCP租约机制中继代理工作原理功能与优势 我们今天来计网的DHCP&#xff1a; 什么是DHCP DHCP&#xff08;Dynamic Host Configuration Protocol&…

Python11 使用爬虫实现图书250排行榜信息爬取

1.什么是网络爬虫 Python爬虫是使用Python编程语言编写的程序&#xff0c;它能自动从互联网上抓取数据。这类程序一般利用网络请求来访问网站&#xff0c;解析网站的HTML或其他格式的内容&#xff0c;提取出有用的数据&#xff0c;有时还会进行后续的数据处理或存储。 Python…