• PHP算法学习(2) 轮训加权算法


    2019年1月8日16:10:51

    svn地址:svn://gitee.com/zxadmin/live_z    代码在code里面

    <?php
    
    /*
     * 加权轮训算法
     * 
     * 
     * $arr = array(
      array('id' => 'A', 'weight' => 3),
      array('id' => 'B', 'weight' => 3),
      array('id' => 'C', 'weight' => 6),
      array('id' => 'D', 'weight' => 4),
      array('id' => 'E', 'weight' => 1),
      );
     * $arr = array(
      array('id' => '192.168.1.1', 'weight' => 3),
      array('id' => '192.168.1.2', 'weight' => 3),
      array('id' => '192.168.1.3', 'weight' => 6),
      array('id' => '192.168.1.4', 'weight' => 4),
      array('id' => '192.168.1.5', 'weight' => 1),
      );
     */
    
    class ZxWeightedRoundRobin {
    
        private static $weightArray = array();
        private static $currentIndex = -1; //代表上一次选择的服务器
        private static $gcd; //表示集合S中所有服务器权值的最大公约数
        private static $currentWeight = 0; //当前调度的权值
        private static $maxWeight; //最大元素的值
        private static $count; //总元素个数
    
        public function __construct(array $weightArray) {
            self::$weightArray = $weightArray;
            self::$gcd = self::getGcd(self::$weightArray);
    //        p(self::$gcd);
        }
    
        /*
         * 
         * 算法的原理是:在服务器数组S中,首先计算所有服务器权重的最大值max(S),以及所有服务器权重的最大公约数gcd(S)。
          index表示本次请求到来时,选择的服务器的索引,初始值为-1;current_weight表示当前调度的权值,初始值为max(S)。
          当请求到来时,从index+1开始轮询服务器数组S,找到其中权重大于current_weight的第一个服务器,用于处理该请求。记录其索引到结果序列中。
          在轮询服务器数组时,如果到达了数组末尾,则重新从头开始搜索,并且减小current_weight的值:current_weight -= gcd(S)。如果current_weight等于0,则将其重置为max(S)。
         * 参考博客:https://blog.csdn.net/gqtcgq/article/details/52076997
         * https://blog.csdn.net/jjavaboy/article/details/45604569
         */
    
        public function getWeight() {
            while (true) {
                self::$currentIndex = ((int) self::$currentIndex + 1) % (int) self::$count;
                if (self::$currentIndex == 0) {
                    self::$currentWeight = (int) self::$currentWeight - (int) self::$gcd;
                    if (self::$currentWeight <= 0) {
                        self::$currentWeight = (int) self::$maxWeight;
                        if (self::$currentWeight == 0) {
                            return null;
                        }
                    }
                }
    //            p(self::$currentIndex);
                if ((int) (self::$weightArray[self::$currentIndex]['weight']) >= self::$currentWeight) {
                    return self::$weightArray[self::$currentIndex];
                }
            }
        }
    
        //获取最大公约数 Greatest common divisor  最大共同被除数
        private static function getGcd(array $weightArray) {
            if (empty($weightArray) || !is_array($weightArray)) {
                throw new Exception('数组不能为空');
            }
            $weight = [];
            //权重只能为正整数
            foreach ($weightArray as $k => $v) {
                if (!is_int($v['weight']) || $v['weight'] <= 0) {
                    throw new Exception('权限不合法');
                }
                $weight[] = $v['weight'];
            }
            $min = min($weight);
            self::$maxWeight = max($weight);
            self::$count = count($weight);
            //如果最小值是1,最小公约数就必定是1
            if ($min == 1) {
                return 1;
            }
            //如果不是1,就每个元素,循环查询对最小值往下做整除处理,如果全可以整除,如果有一个不能就中断
            for ($i = $min; $i > 1; $i--) {
                foreach ($weight as $k1 => $v1) {
                    if ($v1 % $i == 0) {
                        $status = true;
                    } else {
                        $status = false;
                        break;
                    }
                }
                if ($status) {
                    return $i;
                } else {
                    return 1;
                }
            }
        }
    
    }

    这个方法,我理解了最大公约数,但是 getWeight 方法还没有彻底理解,最小公约的话,就只需要修改 

    for ($i = $min; $i > 1; $i--) {遍历就可以

    测试调用方法
    $arr = array(
        array('id' => 'A', 'weight' => 3),
        array('id' => 'B', 'weight' => 3),
        array('id' => 'C', 'weight' => 6),
        array('id' => 'D', 'weight' => 4),
        array('id' => 'E', 'weight' => 2),
    );
    $weight = new ZxWeightedRoundRobin($arr);
    $a = 0;
    $b = 0;
    $c = 0;
    $d = 0;
    $e = 0;
    for ($j = 0; $j < 100; $j++) {
        $weightInfo = $weight->getWeight();
        print_r($weightInfo);
        echo $weightInfo['id'] . '----------------------weight:' . $weightInfo['weight'] . '<br/>';
        if ($weightInfo['id'] == 'A') {
            $a++;
        }
        if ($weightInfo['id'] == 'B') {
            $b++;
        }
        if ($weightInfo['id'] == 'C') {
            $c++;
        }
        if ($weightInfo['id'] == 'D') {
            $d++;
        }
        if ($weightInfo['id'] == 'E') {
            $e++;
        }
    }
    echo 'A:' . $a . '<br/>';
    echo 'B:' . $b . '<br/>';
    echo 'C:' . $c . '<br/>';
    echo 'D:' . $d . '<br/>';
    echo 'E:' . $e . '<br/>';
    exit;
     
  • 相关阅读:
    62. Unique Paths
    102. Binary Tree Level Order Traversal
    3、公共接口不应该使用太过频繁,当有大量类型实现公共接口时,应当避免通过公共接口调用对象
    2、Task 使用 ContinueWith 而不要使用 Wait
    1、使用 as 而不要用 is
    VS 超级好用的 Ctrl E E
    一个好用的分组算法2
    java 字典 map 和 list.forEach
    mongo windows 安装
    mongo repository
  • 原文地址:https://www.cnblogs.com/zx-admin/p/10239570.html
Copyright © 2020-2023  润新知