分治策略——算法

作者: 浪尖的游鱼 | 来源:发表于2019-03-19 17:06 被阅读5次

    分而治之:据不同的成因选择不同的解决方案。
    成语大全如是说。而似乎分治只借了这个成语的名,意思却偏向于问题的拆解再合并,就是把一个复杂的问题分解成多个相同或相似的子问题,再把子问题分解成更小的问题。这种分解问题的思维,。这里先埋一个雷:MapReduce,游鱼过会再提。

    从算法开始

    No.1 经典排序算法——快速排序

    当有人问起:你知道哪几种排序算法啊?大多说人不加思索都能说出三种:冒泡排序(你要是说你只知道选择和插入。。。我估计也不太可能)、选择排序、插入排序。快速排序就是对冒泡排序的一次改进。
    冒泡排序是两两比较,当两两不符合当前规定的顺序时,则交换两者的位置。而快速排序就是选定一个基准值,假设从小到大,基准值左边的如果比基准值大就放到右边,基准值左边的如果比基准值小就放到右边,然后在左右两边再循环这个过程。
    如下图所示:


    快速排序

    算法:(备注,相对于图片局部优化了,减少了交换的次数)

    #!usr/bin/c++
    #include <iostream>
     
    using namespace std;
     #需要快排的数组a,数组第一位low,数组最后一位high。
    void Qsort(int a[], int low, int high)
    {
    #初始数组第一位low>=数组最后一位high,说明这一层排序已经到了最小的字元:数组内单个元素。
        if(low >= high)
        {
            return;
        }
        int first = low;
        int last = high;
        int key = a[first];/*用数组的第一个记录作为枢轴*/
     
        while(first < last)
        {
            while(first < last && a[last] >= key)
            {
                --last;
            }
     
            a[first] = a[last];/*将比第一个小的移到低端*/
     
            while(first < last && a[first] <= key)
            {
                ++first;
            }
             
            a[last] = a[first];/*将比第一个大的移到高端*/
        }
        a[first] = key;/*枢轴保存到first处,此时因为first一路走来保证first前面的小于key,last一路走来保证last后面的大于key,且直到最后first遇到了last*/
    /*对第一位到枢纽的前一位进行二次快排*/
        Qsort(a, low, first-1);
    /*对最后一位到枢纽的后一位进行二次快排*/
        Qsort(a, first+1, high);
    }
    int main()
    {
        int a[] = {57, 68, 59, 52, 72, 28, 96, 33, 24};
        Qsort(a, 0, sizeof(a) / sizeof(a[0]) - 1);
        for(int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
        {
            cout << a[i] << "";
        }
         
        return 0;
    }/*参考数据结构p274(清华大学出版社,严蔚敏)*/
    

    至于对经典快速排序算法的再优化,鱼就不说了,爱看看吧,十分杂乱且刺激。

    No.2 经典排序算法——归并排序

    快排是分治法从全局有序化(左边小右边大)逐步局部有序化(小的是唯一一个,大的也是唯一一个,那这三个数不就排好序了吗)的排序,归并则是从局部有序化(从两个数开始排好序)逐步全局有序化(全部都排好序)的过程。
    因为局部是有序的,所以归并排序是用的以下的手法:


    归并排序
    #!/usr/bin/python
    def MergeSort(lists):
        if len(lists) <= 1:
            return lists
        num = int( len(lists) / 2 )
        left = MergeSort(lists[:num])
        right = MergeSort(lists[num:])
        return Merge(left, right)
    def Merge(left,right):
        r, l=0, 0
        result=[]
        while l<len(left) and r<len(right):
            if left[l] < right[r]:
                result.append(left[l])
                l += 1
            else:
                result.append(right[r])
                r += 1
        result += list(left[l:])
        result += list(right[r:])
        return result
    print(MergeSort([1, 2, 3, 4, 5, 6, 7, 90, 21, 23, 45]))
    #from 百科,不得不说这些写百科的也真的是随手,歪门邪道的错误
    

    经过函数式的洗礼

    绝大多数的高级语言都带入了Map(映射)函数、Reduce(归约)函数的理念

    #!/usr/bin/js
    //array.map(function(currentValue,index,arr), thisValue)
    //currentValue=>当前元素的值,index=>当前元素的索引,arr=>当前数组对象,thisValue=>作为执行回调使用
    //例子
    var numbers = [4, 9, 16, 25];
    
    function myFunction() {
        x = document.getElementById("demo")
        x.innerHTML = numbers.map(Math.sqrt);
    }
    //from runoob
    
    #!/usr/bin/js
    //array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
    //比Map多了total作为归并后的返回值。
    //例子
    var numbers = [65, 44, 12, 4];
     
    function getSum(total, num) {
        return total + num;
    }
    function myFunction(item) {
        document.getElementById("demo").innerHTML = numbers.reduce(getSum);
    }
    //from runoob
    

    先回到最一开始归并排序的逻辑上去——可以看到MergeSort()是在用递归分解问题,即一个大问题分解成一个小问题。而Merge则是在归并,把有序的小问题合并成一个有序的大问题,因为小问题是有序的,所以排序成本极低(小于n)。由此对比下Map和Reduce的函数逻辑,尽管排序少了对小问题的Map映射处理,也是实现了Reduce的思想进行了归约,假设现在有一个一百万无序的数组,正常的排序算法时间复杂度都在nlgn~n^2之间不定,如果用一台电脑去处理,可能要几个小时的时间。而归并排序在Reduce的过程中成本极低,则可以采用分布式处理的方式,先把问题Map出去,交给服务器集群进行处理,最后再Reduce回来得到最后的结果。
    对,就是这样分治策略是分布式系统的逻辑基础,现如今大多数分布式处理都来源于MapReduce思想,由此游鱼还认识了Lisp语言。
    在MapReduce里,Map处理的是原始数据,自然是杂乱无章的,每条数据之间互相没有关系;到了Reduce阶段,数据是以key后面跟着若干个value来组织的,这些value有相关性,至少它们都在一个key下面,于是就符合函数式语言里map和reduce的基本思想了。去借用MapReduce模型的话,开发人员只需要考虑如何进行数据处理,提取特征,最后再考虑如何归纳特征。开发人员不用考虑如何并发的问题。


    MapReduce

    落地到编程模型

    分布式存储HDFS——分布式处理MapReduce
    这方面鱼推荐大家多去阅读文献,不献丑了。只大概说说,复制一下个人之前Apache Storm的笔记

    Apache Storm

    一 优势

    • Apache 产品通用优势:可以通过线性增加资源来保持性能
    • 适用性、语言普适性、分布式处理快的优势、操作智能
    • 优秀的防呆措施

    二、理念

    理念

    Input data source: 数据源
    Spout: 流的源,通过编写 Spout 以从数据源读取数据 Bolt:逻辑处理单元, Spout 将数据传递到 Bolt 和 Bolt过程,并产生新的数据流。
    Bolt 可以拍行过滤、聚合、加入,并与数据 源和数据库进行交互
    Tuple:有序元素的列表
    Stream:元组的无序序列

    关键词:拓扑和路由

    三、集群架构

    集群架构

    Apache Storm 的集群架构,采用了主从设备模式。这种模式参照于?
    Zookeeper framework:协助 Supervisor 和 nimbus 交互
    Nimbus : Storm 集群的主节点,又称Master。而工作结点分发数据并监控故障
    Supervisor:工作节点又称 Workers,负责管理工作进程以完成分配的任务
    Worker process:工作进程,其执行与特定拓扑相关的任务。其创建执行器,并要求它们完成任务
    Execute:执行器。由工作进程产生的单个线程,用于特定的spout与 bolt
    Task:任务,实际执行数据处理。它是个 spout 或 bolt

    四、工作流程

    工作流程

    相关文章

      网友评论

        本文标题:分治策略——算法

        本文链接:https://www.haomeiwen.com/subject/pywhmqtx.html