Java和C++在函数参数传递上的不同

故事的起源

起源于在leetcode上面刷题,刷到第39题Combination Sum。
Combination Sum
这道题是一道经典的回溯问题,一个被票选为最佳答案的解决方案如下:

public class Solution {
    public List<List<Integer>> combinationSum(int[] nums, int target) {
        List<List<Integer>> list = new ArrayList<>();
        Arrays.sort(nums);
        backtrack(list, new ArrayList<>(), nums, target, 0);
        return list;
    }

    private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, int remain, int start){
        if(remain < 0) return;
        else if(remain == 0) list.add(new ArrayList<>(tempList));
        else{ 
            for(int i = start; i < nums.length; i++){
                tempList.add(nums[i]);
                backtrack(list, tempList, nums, remain - nums[i], i); // not i + 1 because we can reuse same elements
                tempList.remove(tempList.size() - 1);
            }
        }
    }
}

当然还是有更加快速的方法的,请提交后参见More Details里面那个14ms的方法。

我的内心活动

因为我是以前用C++,最近才开始用Java的,当做到这一道题目的时候,我不禁心头一震,要是在整个解空间里不停地调用函数backtrack,是不是所有的参数都要被复制好多好多份,放在内存里,当测试用例特别大的时候,会不会造成很高的空间复杂度?

这时我想起了C++的引用传值大法,这样的话就不会在调用函数的时候把那些参数变量复制一份,大家一起公用一份就可以了,那么我自然而然的想到,Java中的引用参数是怎么玩的?

对Java面向对象理解

然而我的疑惑很快就解开了,大家可以看《Head First Java》这本书的55页到58页。Java中的每一个变量,本质上都是一个“遥控器”。一般声明一个变量比如 tv a; ,表示我买了一个新的遥控器a(注意,前面的tv应该理解成遥控器a是专用来遥控电视的,遥控不了空调等其他设备),a = new tv; 表示家里新买了一台电视,然后我们用我们已经有的遥控器来绑定这台电视。

假如有一天遥控器丢了,或者去遥控其他的电视了,那么Java虚拟机会帮助我们回收这台电视。

回到回溯法上面来

那么,显然我对于回溯问题巨大的解空间树的担心是多余的。因为每一次调用函数backtrack,参数其实都只是遥控器而已,遥控器嘛,能占多大的地方呢?表面看上去是一个参数的复制(C++视角),实际上不过是用两个遥控器遥控同一台电视而已(Java视角),电视一直就只占一份内存,遥控器嘛,多几个又怎么样呢?

我想这大概就是这么多人喜欢Java的原因之一吧。)——来自一个Java菜鸟的无病呻吟。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值