if elseif else条件语句的计算量问题

我们经常用if elseif else这种条件语句去做分支处理,之前遇到这种语句时就有点困惑,哪种条件语句放前面,哪种放后面,不同顺序是否有计算量和效率上的不同?在计算量小的时候,其实分别是不大的,但是随着代码量的不断增多,运算量越来越大,特别是将来大数据和机器学习等海量数据处理的时候,算法的优势就更加明显.Ps: alphaGo Zero用的处理器只有alphaGo的十分之一,算力不强大,但算法的优势却一举让它成功打败阿尔法狗,也印证了算法之于算力的关系,可见算法的重要性.这次用一个小例子来说明代码的计算量优化的问题.

 

假设我们有两个箱子,每个箱子里有从1到10一共10个球,同时从两个箱中分别取一个球,如果两个数都大于8,则中奖.现在要写一个代码,判断是否中奖.

 

思路:我们知道中奖的概率是(2/10)^2=0.04,是一个小概率事件,所以我们分别从两个方向来统计代码的计算量,一个从大概率开始判断,一个从小概率开始判断.

 

从大概率开始判断

//运算次数初始化
$times = 0;

//先判断大概率事件
for ($i=1;$i<=10;$i++) {
	for ($j=1;$j<=10;$j++) {
		if ($i<=8 && $j<=8) { //如果两个数都小于等于8,则这次判断的运算量为3,运算量+3
			$times += 3;
		} elseif ($i<=8 && $j>8) {/*如果第一个数小于等于8第二个数大于8,则这次判断的计算量为6
			(因为它首先判断了自己不符合上一个条件,此时计算量为3,然后在这里又做了
			一个计算量为3的第二次判断,所以总共的计算量为6)*/
			$times += 6;
		} elseif ($i>8 && $j<=8) {/*到达这里用了7次运算,这里第一个数大于8,所以在到达第一个条件时
			的第一个判断时就为假,而由于php的短路与机制,后面的第二个判断就没有执行,所以第一个条件
			执行了2次运算,同理,第二个条件也执行了2次运算,到达本条件时执行了3次运算,所以一共是7次运算*/
			$times += 7;
		} else {//到这里一共经历了2+2+2=6次判断
			$times += 6;
		}
	}
}

echo $times; //输出运算量,一共424次运算

 

从小概率开始判断

$times = 0;
//先判断小概率事件
for ($i=1;$i<=10;$i++) {
	for ($j=1;$j<=10;$j++) {
		if ($i>8 && $j>8) { //如果两个数都大于8,则这次判断的运算量为3,运算量+3
			$times += 3;
		} elseif ($i>8 && $j<=8) { /*如果第一个数大于8第二个数小于等于8,则这次判断的计算量为6
			(因为它首先判断了自己不符合上一个条件,此时计算量为3,然后在这里又做了
			一个计算量为3的第二次判断,所以总共的计算量为6)*/
			$times += 6;
		} elseif ($i<=8 && $j<=8) { /*到达这里用了7次运算,这里第一个数小于等于8,所以在到达第一个条件时
			的第一个判断时就为假,而由于php的短路与机制,后面的第二个判断就没有执行,所以第一个条件
			执行了2次运算,同理,第二个条件也执行了2次运算,到达本条件时执行了3次运算,所以一共是7次运算*/
			$times += 7;
		} else { //到这里一共经历了2+2+2=6次判断
			$times += 6;
		}
	}
}

echo $times; //652次判断

 

可以看出,从概率大的条件开始判断时,运算的次数要少,在这个案例中少20%,也就是说节约了20%的算力,如果是线性的话,则提升了25%的性能.

 

我们反过来试一试,假设两个球都小于2的时候为中奖,分别按大小概率实验一下.

小概率

$times = 0;

//先判断小概率事件
for($i=1;$i<=10;$i++){
	for($j=1;$j<=10;$j++){
		if($i<=2 && $j<=2){
			$times += 3;
		}elseif($i<=2 && $j>2){
			$times += 6;
		}elseif($i>2 && $j<=2){
			$times += 7;
		}else{
			$times += 6;
		}
	}
}

echo $times; //496次判断

大概率

$times = 0;
//先判断大概率事件
for($i=1;$i<=10;$i++){
	for($j=1;$j<=10;$j++){
		if($i>2 && $j>2){
			$times += 3;
		}elseif($i>2 && $j<=2){
			$times += 6;
		}elseif($i<=2 && $j<=2){
			$times += 7;
		}else{
			$times += 6;
		}
	}
}

echo $times; //412次判断

可以看到,从大概率开始判断仍然 比 从小概率开始判断 节省了算力,在这个案例中,节省了约19%.

 

但是,可以看出,无论是大概率还是小概率,以2为分界线的运算量 比 以8为分界线的运算量更少.

412/496 vs. 424/652,虽然中奖概率都是一样的.这是个很有意思的问题.

大概的原因是,从一开始判断的顺序问题,因为数字是从1到10这样排列的,而下面的方法从小数字开始判断的,所以就很容易进入前面的分支,节约了一些算力.

 

思考:

1, 大概率;

2, 顺着数字变化的方向来判断---所以在指定获奖规则的时候可以参考顺着数字变化顺序来;

3, 逻辑或(还有 or die这种),逻辑与的短路问题,节约时间.

转载于:https://my.oschina.net/u/3412738/blog/1554969

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用策略模式和工厂方法来避免大if else的问题。策略模式将每个条件分支封装成一个独立的策略类,然后由一个上下文类来调用这些策略类,从而避免了大的if else嵌套。而工厂方法则可以根据不同的条件创建不同的对象,从而避免了大的if else判断。这两种方法都可以提高代码的可读性和可维护性。 举个例子,假设我们需要根据不同的用户类型来计算折扣,如果使用if else语句,代码可能会变得非常复杂。而如果使用策略模式和工厂方法,我们可以将每个用户类型的折扣计算封装成一个独立的策略类,然后由一个上下文类来调用这些策略类,从而避免了大的if else嵌套。 ```java // 策略接口 interface DiscountStrategy { double calculateDiscount(double price); } // 不同的策略类 class VIPDiscountStrategy implements DiscountStrategy { public double calculateDiscount(double price) { return price * 0.8; } } class NormalDiscountStrategy implements DiscountStrategy { public double calculateDiscount(double price) { return price * 0.9; } } // 工厂类 class DiscountStrategyFactory { public static DiscountStrategy createDiscountStrategy(String userType) { if (userType.equals("VIP")) { return new VIPDiscountStrategy(); } else { return new NormalDiscountStrategy(); } } } // 上下文类 class Order { private double price; private String userType; public Order(double price, String userType) { this.price = price; this.userType = userType; } public double calculateTotalPrice() { DiscountStrategy discountStrategy = DiscountStrategyFactory.createDiscountStrategy(userType); return discountStrategy.calculateDiscount(price); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值